﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Apusic技术顾问园地-文章分类-WEB开发</title><link>http://www.blogjava.net/zhuyuanxiang/category/23753.html</link><description>解决Apusic使用问题</description><language>zh-cn</language><lastBuildDate>Sun, 16 Sep 2007 09:43:01 GMT</lastBuildDate><pubDate>Sun, 16 Sep 2007 09:43:01 GMT</pubDate><ttl>60</ttl><item><title>HTTP服务器状态代码定义（Status Code Definitions） （转）</title><link>http://www.blogjava.net/zhuyuanxiang/articles/145529.html</link><dc:creator>朱远翔-Apusic技术支持工程师</dc:creator><author>朱远翔-Apusic技术支持工程师</author><pubDate>Sun, 16 Sep 2007 06:30:00 GMT</pubDate><guid>http://www.blogjava.net/zhuyuanxiang/articles/145529.html</guid><wfw:comment>http://www.blogjava.net/zhuyuanxiang/comments/145529.html</wfw:comment><comments>http://www.blogjava.net/zhuyuanxiang/articles/145529.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhuyuanxiang/comments/commentRss/145529.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhuyuanxiang/services/trackbacks/145529.html</trackback:ping><description><![CDATA[<strong><span>本文是转来的，但是本文作者不详，如果原作者看到可以与我联系，尊重作者版权。<br />
<br />
1.1 </span></strong><strong><span>消息<span>1xx</span>（<span>Informational 1xx</span>）</span></strong><span> <br />
</span><span>该类状态代码用于表示临时回应。临时回应由状态行（<span>Status-Line</span>）及可选标题组成， 由空行终止。<span>HTTP/1.0</span>中没有定义任何<span>1xx</span>的状态代码，所以它们不是对<span>HTTP/1.0</span>请求的 　　合法回应。实际上，它们主要用于实验用途，这已经超出本文档的范围。<span> <br />
<strong>1.2 </strong></span><strong>成功<span>2xx</span>（<span>Successful 2xx</span>）</strong><span> <br />
</span>表示客户端请求被成功接收、理解、接受。<span> <br />
<strong>200 OK</strong> <br />
</span>请求成功。回应的信息依赖于请求所使用的方法，如下：<span> <br />
GET </span>要请求的资源已经放在回应的实体中了。<span> <br />
HEAD </span>没有实体主体，回应中只包括标题信息。</span><span></span><span> <br />
POST </span><span>实体（描述或包含操作的结果）。<span> <br />
<strong>201 Created</strong> <br />
</span>请求完成，结果是创建了新资源。新创建资源的<span>URI</span>可在回应的实体中得到。原始服务器应在发出该状态代码前创建该资源。如果该操作不能立即完成，服务器必须在该资源可用时在回应主体中给出提示，否则，服务器端应回应<span>202</span>（可被接受）。<span> <br />
</span>在本文定义的方法，只有<span>POST</span>可以创建资源。<span> <br />
<strong>202 Accepted</strong> <br />
</span>请求被接受，但处理尚未完成。请求可能不一定会最终完成，有可能被处理过程随时中断，在这种情况下，没有办法在异步操作中重新发送状态代码。<span> <br />
202</span>回应是没有义务的，这样做的目的是允许服务器不必等到用户代理和服务器间的连接结束，就可以响应其它过程的请求（象每天运行一次的，基于批处理的过程）。<span> <br />
</span>在某些回应中返回的实体中包括当前请求的状态指示、状态监视器指针或用户对请求能否实现的评估信息。<span><br />
<strong>204 No Content</strong> <br />
</span>服务器端已经实现了请求，但是没有返回新的信息。如果客户是用户代理，则勿需为此更新自身的文档视图。该回应主要是为了在不影响用户代理激活文档视图的前提下，进行<span>script</span>语句的输入及其它操作。该回应还可能包括新的、以实体标题形式表示的元信息，它可被当前用户代理激活视图中的文档所使用。<span> <br />
<strong>1.3 </strong></span><strong>重定向（<span>Redirection 3xx</span>）</strong><span> <br />
</span>该类状态码表示用户代理要想完成请求，还需要发出进一步的操作。这些操作只有当后跟的请求是<span>GET</span>或<span>HEAD</span>时，才可由用户代理来实现，而不用与用户进行交互。用户代理永远也不要对请求进行<span>5</span>次以上的重定向操作，这样可能导致无限循环。<span> <br />
<strong>300 Multiple Choices</strong> <br />
</span>该状态码不被<span>HTTP/1.0</span>的应用程序直接使用，只是做为<span>3xx</span>类型回应的缺省解释。存在多个可用的被请求资源。<span> <br />
</span>除非是<span>HEAD</span>请求，否则回应的实体中必须包括这些资源的字符列表及位置信息，由用户或用户代理来决定哪个是最适合的。<span> <br />
</span>如果服务器有首选，它应将对应的<span>URL</span>信息存放在位置域（<span>Location field</span>）处，用户代理会根据此域的值来实现自动的重定向。<span> <br />
<strong>301 Moved Permanently </strong><br />
</span>请求到的资源都会分配一个永久的<span>URL</span>，这样就可以在将来通过该<span>URL</span>来访问此资源。有编辑链接功能的客户端会尽可能地根据服务器端传回的新链接而自动更新请求<span>URI</span>。 新的<span>URL</span>必须由回应中的位置域指定。除非是<span>HEAD</span>请求，否则回应的实体主体 　　（<span>Entity-Body</span>）必须包括对新<span>URL</span>超链接的简要描述。<span> <br />
</span>如果用<span>POST</span>方法发出请求，而接收到<span>301</span>回应状态码。在这种情况下，除非用户确认，否则用户代理不必自动重定向请求，因为这将导致改变已发出请求的环境。<span> <br />
</span>注意：当在接收到<span>301</span>状态码后而自动重定向<span>POST</span>请求时，一些现存的用户代理会错误地将其改为<span>GET</span>请求。<span> <br />
<strong>302 Moved Temporarily<br />
</strong></span>请求到的资源在一个不同的<span>URL</span>处临时保存。因为重定向有时会被更改，客户端应继续用请求<span>URI</span>来发出以后的请求。新的<span>URL</span>必须由回应中的位置域指定。除非是<span>HEAD</span>请求，否则回应的实体主体 （<span>Entity-Body</span>）必须包括对新<span>URL</span>超链接的简要描述。<span> <br />
</span>如果用<span>POST</span>方法发出请求，而接收到<span>302</span>回应状态码。在这种情况下，除非用户确认，否则用户代理不必自动重定向请求，因为这将导致改变已发出请求的环境。<span> <br />
</span>注意：当在接收到<span>302</span>状态码后而自动重定向<span>POST</span>请求时，一些现存的用户代理会错误地将其改为<span>GET</span>请求。<span> <br />
<strong>304 Not Modified </strong><br />
</span>如果客户端成功执行了条件<span>GET</span>请求，而对应文件自<span>If-Modified-Since</span>域所指定的日期以来就没有更新过，服务器应当回应此状态码，而不是将实体主体发送给客户端。回应标题域中只应包括一些相关信息，比如缓存管理器、与实体最近更新（<span>entity's Last-Modified</span>）日期无关的修改。相关标题域的例子有：日期、服务器、过期时间。每当<span>304</span>回应中给出的域值发生变化，缓存都应当对缓存的实体进行更新。<span> <br />
<strong>1.4 </strong></span><strong>客户端错误（<span>Client Error </span>）<span>4xx </span></strong><span><br />
4xx</span>类的状态码表示客户端发生错误。如果客户端在收到<span>4xx</span>代码时请求还没有完成，它应当立即终止向服务器发送数据。除了回应<span>HEAD</span>请求外，不论错误是临时的还是永久的，服务器端都必须在回应的实体中包含错误状态的解释。这些状态码适用于任何请求方法。<span> <br />
</span>注意：如果客户端正在发送数据，服务器端的<span>TCP</span>实现应当小心，以确保客户端在关闭输入连接之前收到回应包。如果客户端在关闭后仍旧向服务器发送数据，服务器会给客户　　端发送一个复位包，清空客户端尚未处理的输入缓冲区，以终止<span>HTTP</span>应用程序的读取、解释活动。<span> <br />
<strong>400 </strong></span><strong>非法请求（<span>Bad Request</span>）</strong><span> <br />
</span>如果请求的语法不对，服务器将无法理解。客户端在对该请求做出更改之前，不应再次向服务器重复发送该请求。<span> <br />
<strong>401 </strong></span><strong>未授权（<span>Unauthorized</span>）</strong><span> <br />
</span>请求需要用户授权。回应中的<span>WWW-Authenticate</span>标题域（<span>10.16</span>节）应提示用户以授权方式请求资源。客户端应使用合适的授权标题域（<span>10.2</span>节）来重复该请求。如果请求中已经包括了授权信任信息，那回应的<span>401</span>表示此授权被拒绝。如果用户代理在多次尝试之后，回应一样还是返回<span>401</span>状态代码，用户应当察看一下回应的实体，因为在实体中会包括一些相关的动态信息。<span>HTTP</span>访问授权会在<span>11</span>节中解释。<span> <br />
<strong>403 </strong></span><strong>禁止（<span>Forbidden</span>）</strong><span> <br />
</span>服务器理解请求，但是拒绝实现该请求。授权对此没有帮助，客户端应当停止重复发送此请求。如果不是用<span>HEAD</span>请求方法，而且服务器端愿意公布请求未被实现原因的前提下，服务器会将拒绝原因写在回应实体中。该状态码一般用于服务器端不想公布请求被拒绝的细节或没有其它的回应可用。<span> <br />
<strong>404 </strong></span><strong>没有找到（<span>Not Found</span>）</strong><span> <br />
</span>服务器没有找到与请求<span>URI</span>相符的资源。<span>404</span>状态码并不指明状况是临时性的还是永久性的。如果服务器不希望为客户端提供这方面的信息，还回应<span>403</span>（禁止）状态码。<span> <br />
<strong>1.5 </strong></span><strong>服务器错误（<span>Server Error </span>）<span>5xx <br />
</span></strong>回应代码以<span>&#8216;5&#8217;</span>开头的状态码表示服务器端发现自己出现错误，不能继续执行请求。如果客户端在收到<span>5xx</span>状态码时，请求尚未完成，它应当立即停止向服务器发送数据。除了回应<span>HEAD</span>请求外，服务器应当在其回应实体中包括对错误情况的解释、并指明是临时性的还永久性的。<span> <br />
</span>这类回应代码没有标题域，可适用于任何请求方法。<span><br />
<strong>500 </strong></span><strong>服务器内部错误（<span>Internal Server Error</span>）</strong><span> <br />
</span>服务器碰到了意外情况，使其无法继续回应请求。<span> <br />
<strong>501 </strong></span><strong>未实现（<span>Not Implemented</span>）</strong><span> <br />
</span>服务器无法提供对请求中所要求功能的支持。如果服务器无法识别请求方法就会回应此状态代码，这意味着不能回应请求所要求的任何资源。<span> <br />
<strong>502 </strong></span><strong>非法网关（<span>Bad Gateway</span>） </strong><span><br />
</span>充当网关或代理的服务器从要发送请求的上游（<span>upstream</span>）服务器收到非法的回应。<span> <br />
<strong>503 </strong></span><strong>服务不可用（<span>Service Unavailable</span>）</strong><span> <br />
</span>服务器当前无法处理请求。这一般是由于服务器临时性超载或维护引起的。该状态码暗示情况是暂时性的，要产生一些延迟。<span> <br />
</span>注意：<span>503</span>状态码并没有暗示服务器在超载时一定要返回此状态码。一些服务器可能希望在超载时采用简单处理，即断掉连接。<span> </span></span><img src ="http://www.blogjava.net/zhuyuanxiang/aggbug/145529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhuyuanxiang/" target="_blank">朱远翔-Apusic技术支持工程师</a> 2007-09-16 14:30 <a href="http://www.blogjava.net/zhuyuanxiang/articles/145529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JSP中基于Session的在线用户统计分析（转）</title><link>http://www.blogjava.net/zhuyuanxiang/articles/127460.html</link><dc:creator>朱远翔-Apusic技术支持工程师</dc:creator><author>朱远翔-Apusic技术支持工程师</author><pubDate>Mon, 02 Jul 2007 03:31:00 GMT</pubDate><guid>http://www.blogjava.net/zhuyuanxiang/articles/127460.html</guid><wfw:comment>http://www.blogjava.net/zhuyuanxiang/comments/127460.html</wfw:comment><comments>http://www.blogjava.net/zhuyuanxiang/articles/127460.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhuyuanxiang/comments/commentRss/127460.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhuyuanxiang/services/trackbacks/127460.html</trackback:ping><description><![CDATA[<p>　JSP作为后起之秀能够在服务器编程环境中占据一定地位，是和它良好支持一系列业界标准密切相关的。Session就是它提供的基础设施之一。作为一个程序员，你可以不介意具体在客户端是如何实现，就方便的实现简单的基于session的用户管理。现在对于处理在线用户，有几种不同的处理方法。</p>
<p>　　一种是页面刷新由用户控制，服务器端控制一个超时时间比如30分钟，到了时间之后用户没有动作就被踢出。这种方法的优点是，如果用户忘了退出，可以防止别人恶意操作。缺点是，如果你在做一件很耗时间的事情，超过了这个时间限制，submit的时候可能要再次面临登陆。如果原来的叶面又是强制失效的话，就有可能丢失你做的工作。在实现的角度来看，这是最简单的，Server端默认实现的就是这样的模式。</p>
<p>　　另一种方式是，站点采用框架结构，有一个Frame或者隐藏的iframe在不断刷新，这样你永远不会被踢出，但是服务器端为了判断你是否在线，需要定一个发呆时间，如果超过这个发呆时间你除了这个自动刷新的页面外没有刷新其他页面的话，就认为你已经不在线了。采取这种方式的典型是xici.net。 他的优点是可以可以利用不断的刷新实现一些类似server-push的功能，比如网友之间发送消息。</p>
<p>　　不管哪一种模式，为了实现浏览当前所有的在线用户，还需要做一些额外的工作。servlet API中没有得到Session列表的API。</p>
<p>　　可以利用的是Listener. Servlet 2.2和2.3规范在这里略微有一些不一样。2.2中HttpSessionBindingListener可以实现当一个HTTPSession中的Attribute变化的时候通知你的类。而2.3中还引入了HttpSessionAttributeListener.鉴于我使用的环境是Visual age for java 4和JRun server 3.1,他们还不直接支持Servlet 2.3的编程，这里我用的是HttpSessionBindingListener.</p>
<p>　　需要做的事情包括做一个新的类来实现HttpSessionBindingListener接口。这个接口有两个方法：</p>
<p>public void valueBound(HttpSessionBindingEvent event)<br>public void valueUnbound(HttpSessionBindingEvent event) </p>
<p>　　当你执行Session.addAttribute(String,Object)的时候，如果你已经把一个实现了HttpSessionBindingListener接口的类加入为Attribute,Session会通知你的类，调用你的valueBound方法。相反，Session.removeAttribute方法对应的是valueUndound方法。</p>
<p>public class HttpSessionBinding implements javax.servlet.http.HttpSessionBindingListener <br>{<br>　ServletContext application = null;</p>
<p>　public HttpSessionBinding(ServletContext application)<br>　{<br>　　super();<br>　　if (application ==null)<br>　　　throw new IllegalArgumentException("Null application is not accept.");<br>　　this.application = application;<br>　}</p>
<p>　public void valueBound(javax.servlet.http.HttpSessionBindingEvent e) <br>　{ <br>　　Vector activeSessions = (Vector) application.getAttribute("activeSessions");<br>　　if (activeSessions == null)<br>　　{<br>　　　activeSessions = new Vector();<br>　　}</p>
<p>　　JDBCUser sessionUser = (JDBCUser)e.getSession().getAttribute("user");<br>　　if (sessionUser != null)<br>　　{<br>　　　activeSessions.add(e.getSession());<br>　　}<br>　　application.setAttribute("activeSessions",activeSessions);<br>　}</p>
<p>　public void valueUnbound(javax.servlet.http.HttpSessionBindingEvent e) <br>　{<br>　　JDBCUser sessionUser = (JDBCUser)e.getSession().getAttribute("user");<br>　　if (sessionUser == null)<br>　　{<br>　　　Vector activeSessions = (Vector) application.getAttribute("activeSessions");<br>　　　if (activeSessions != null)<br>　　　{<br>　　　　activeSessions.remove(e.getSession().getId());<br>　　　　application.setAttribute("activeSessions",activeSessions);<br>　　　}<br>　　}<br>　}<br>} </p>
<p>　　假设其中的JDBCUser类是一个任意User类。在执行用户登录时，把User类和HttpSessionBinding类都加入到Session中去。</p>
<p>　　这样，每次用户登录后，在application中的attribute "activeSessions"这个vector中都会增加一条记录。每当session超时，valueUnbound被触发，在这个vector中删去将要被超时的session.<br>&nbsp;<br>public void login()<br>throws ACLException,SQLException,IOException<br>{<br>　/* get JDBC User Class */<br>　if (user != null)<br>　{<br>　　logout();<br>　}<br>　{<br>　　// if session time out, or user didn't login, save the target url temporary.</p>
<p>　　JDBCUserFactory uf = new JDBCUserFactory();</p>
<p>　　if ( (this.request.getParameter("userID")==null) || (this.request.getParameter("password")==null) )<br>　　{<br>　　　throw new ACLException("Please input a valid userName and password.");<br>　　}</p>
<p>　　JDBCUser user = (JDBCUser) uf.UserLogin(<br>　　　this.request.getParameter("userID"),<br>　　　this.request.getParameter("password") );<br>　　　user.touchLoginTime();<br>　　　this.session.setAttribute("user",user);<br>　　　this.session.setAttribute("BindingNotify",new HttpSessionBinding(application));<br>　　}<br>　} </p>
<p>　　Login的时候，把User和这个BindingNotofy目的的类都加入到session中去。logout的时候，就要主动在activeSessions这个vector中删去这个session.</p>
<p>public void logout()<br>throws SQLException,ACLException<br>{<br>　if (this.user == null &amp;&amp; this.session.getAttribute("user")==null)<br>　{<br>　　return;<br>　}</p>
<p>　Vector activeSessions = (Vector) this.application.getAttribute("activeSessions");<br>　if (activeSessions != null)<br>　{<br>　　activeSessions.remove(this.session);<br>　　application.setAttribute("activeSessions",activeSessions);<br>　}</p>
<p>　java.util.Enumeration e = this.session.getAttributeNames();</p>
<p>　while (e.hasMoreElements())<br>　{<br>　　String s = (String)e.nextElement();<br>　　this.session.removeAttribute(s);<br>　}<br>　this.user.touchLogoutTime();<br>　this.user = null;<br>} </p>
<p>　　 这两个函数位于一个HttpSessionManager类中.这个类引用了jsp里面的application全局对象。这个类的其他代码和本文无关且相当长，我就不贴出来了。<br>下面来看看jsp里面怎么用。</p>
<p>　　假设一个登录用的表单被提交到doLogin.jsp, 表单中包含UserName和password域。节选部分片段：</p>
<p>＜%<br>HttpSessionManager hsm = new HttpSessionManager(application,request,response);<br>try<br>{<br>　hsm.login();<br>}<br>catch ( UserNotFoundException e)<br>{<br>　response.sendRedirect("InsufficientPrivilege.jsp?detail=User%20does%20not%20exist.");<br>　return;<br>}<br>catch ( InvalidPasswordException e2)<br>{ <br>　response.sendRedirect("InsufficientPrivilege.jsp?detail=Invalid%20Password");<br>　return;<br>}<br>catch ( Exception e3)<br>{<br>　%＞ Error:＜%=e3.toString() %＞＜br＞<br>　Press ＜a href="login.jsp"＞Here＜/a＞ to relogin.<br>　＜% return;<br>}<br>response.sendRedirect("index.jsp");<br>%＞ </p>
<p>　　再来看看现在我们怎么得到一个当前在线的用户列表。</p>
<p>＜body bgcolor="#FFFFFF"＞<br>＜table cellspacing="0" cellpadding="0" width="100%"＞</p>
<p>＜tr ＞<br>＜td style="width:24px"＞SessionId<br>＜/td＞<br>＜td style="width:80px" ＞User<br>＜/td＞<br>＜td style="width:80px" ＞Login Time<br>＜/td＞<br>＜td style="width:80px" ＞Last access Time<br>＜/td＞<br>＜/tr＞<br>＜%<br>Vector activeSessions = (Vector) application.getAttribute("activeSessions");<br>if (activeSessions == null)<br>{<br>　activeSessions = new Vector();<br>　application.setAttribute("activeSessions",activeSessions);<br>}</p>
<p>Iterator it = activeSessions.iterator();<br>while (it.hasNext())<br>{<br>　HttpSession sess = (HttpSession)it.next();<br>　JDBCUser sessionUser = (JDBCUser)sess.getAttribute("user");<br>　String userId = (sessionUser!=null)?sessionUser.getUserID():"None";<br>%＞<br>＜tr＞<br>＜td nowrap=''＞＜%= sess.getId() %＞＜/td＞<br>＜td nowrap=''＞＜%= userId %＞＜/td＞<br>＜td nowrap=''＞<br>＜%= BeaconDate.getInstance( new java.util.Date(sess.getCreationTime())).getDateTimeString()%＞＜/td＞<br>＜td class="＜%= stl %＞3" nowrap=''＞<br>＜%= BeaconDate.getInstance( new java.util.Date(sess.getLastAccessedTime())).getDateTimeString()%＞＜/td＞<br>＜/tr＞<br>＜%<br>}<br>%＞<br>＜/table＞<br>＜/body＞ </p>
<p>　　以上的代码从application中取出activeSessions，并且显示出具体的时间。其中BeaconDate类假设为格式化时间的类。</p>
<p><br>　　这样，我们得到了一个察看在线用户的列表的框架。至于在线用户列表分页等功能，与本文无关，不予讨论。</p>
<p>　　这是一个非刷新模型的例子，依赖于session的超时机制。我的同事sonymusic指出很多时候由于各个厂商思想的不同，这有可能是不可信赖的。考虑到这种需求，需要在每个叶面刷新的时候都判断当前用户距离上次使用的时间是否超过某一个预定时间值。这实质上就是自己实现session超时。如果需要实现刷新模型，就必须使用这种每个叶面进行刷新判断的方法。</p>
<img src ="http://www.blogjava.net/zhuyuanxiang/aggbug/127460.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhuyuanxiang/" target="_blank">朱远翔-Apusic技术支持工程师</a> 2007-07-02 11:31 <a href="http://www.blogjava.net/zhuyuanxiang/articles/127460.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>