客户请求的处理:HTTP请求报头主讲:刘晓涛议程HTTP请求报头的读取制作所有请求报头的表格了解各种请求报头通过压缩页面减少下载时间区分不同的浏览器类型一个典型的HTTP请求GET/servlet/Search?keywords=servlets+jspHTTP/1.1Accept:image/gif,image/jpg,*/*Accept-Encoding:gzipConnection:Keep-AliveCookie:userID=id456578Host:Referer:User-Agent:Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.0)理解HTTP无疑会有助于更有效地使用servlet和JSP请求报头的读取(HttpServletRequest中的方法)通用方法getHeader(报头名对大小写不敏感)getHeadersgetHeaderNames专用方法getCookiesgetAuthType和getRemoteUsergetContentLengthgetContentTypegetDateHeadergetIntHeader获取相关信息的方法getMethod,getRequestURI,getQueryString,getProtocol缺失报头的检查HTTP1.0所有请求报头都是可选的HTTP1.1仅Host是必需的结论在试图使用由request.getHeader返回的值之前一定要检查它是否为null。Stringval=request.getHeader(Some-Name);if(val!=null){…}制作所有请求报头的表格publicclassShowRequestHeadersextendsHttpServlet{publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{out.println(docType+HTML\n+HEADTITLE+title+/TITLE/HEAD\n+BODYBGCOLOR=\#FDF5E6\\n+H1ALIGN=\CENTER\+title+/H1\n+BRequestMethod:/B+request.getMethod()+BR\n+BRequestURI:/B+request.getRequestURI()+BR\n+BRequestProtocol:/B+request.getProtocol()+BRBR\n+制作所有请求报头的表格(续)TABLEBORDER=1ALIGN=\CENTER\\n+TRBGCOLOR=\#FFAD00\\n+THHeaderNameTHHeaderValue);EnumerationheaderNames=request.getHeaderNames();while(headerNames.hasMoreElements()){StringheaderName=(String)headerNames.nextElement();out.println(TRTD+headerName);out.println(TD+request.getHeader(headerName));}out.println(/TABLE\n/BODY/HTML);}publicvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{doGet(request,response);}}常见HTTP1.1请求报头Accept标示浏览器能够处理的MIME类型可以向不同的客户程序发送不同的内容。例如,PNG文件拥有较好的压缩特性但并不被浏览器广泛支持。servlet可以检查浏览器是否支持PNG文件,如果支持则发送IMGSRC=picture.png..否则发送IMGSRC=picture.gif...。警告:在点击Refresh按钮时,IE会错误在设置这个报头。但在最初的请求中,对这个报头的设置是正确的Accept-Encoding标示浏览器能够处理的编码(如gzip或compress)参见随后的例子常见HTTP1.1请求报头(续)Authorization用于发送受密码保护的页面的用户身份验证信息。应该尽可能使用HTML表单来发送用户名/密码,在会话对象中存储信息;而不是这个报头。因为这种方式会弹出一个小而简练的对话框,许多用户不熟悉它。服务器拥有其他高级的方式来设置受密码保护的页面,无须显式地在servlet中编写相关的代码。常见HTTP1.1请求报头(续)Connection在HTTP1.0中,keep-alive表示浏览器能够处理持续性连接。在HTTP1.1中,持续性连接是默认的。持续性连接表示:对于来自同一客户的相隔时间很近的请求(如与同一页面相关联的图像,或具有框架的页面中的不同单元),服务器可以重用已有的socket。servlet并不能单方面地完成这项工作;要使持续性连接的使用成为可能,它们能够做的就是给予服务器足够的信息。因此,它们应该用setContentLength设置Content-Length(输出的长度使用ByteArrayOutputStream来确定)。Cookie给出之前发送到客户端的cookie。使用getCookies,不要使用getHeader。参见后面的课程。常见HTTP1.1请求报头(续)Host标示最初的URL中给出的主机。在HTTP1.1中这是一个必需的报头。如果您在编写定制的HTTP客户程序,或者使用HTTP/1.1版本telnet到服务器,那么了解这一点十分重要。If-Modified-Since标示仅当在指定的日期之后被改动过时客户才希望获得该页面不要直接处理这种情况,而应实现getLastModified。常见HTTP1.1请求报头(续)Referer引用页面的URL对于流量跟踪有作;许多服务器都记录这项信息也可用来让用户设置相应的参数,然后再返回到跳转过来的页面很容易被哄骗;所以不要将它作为确定付费网站显示了多少次您的标题广告的唯一途径。某些浏览器(Opera),广告过滤器(WebWasher),和个人防火墙(Norton)会屏蔽这个报头User-Agent最好用来鉴定客户的类型浏览器、I-mode的移动电话等。对于Web应用,请尽可能使用其他报头。同样,也很容易被哄骗。参见后面的例子发送经过压缩的Web页面:GzipUtilities.javapublicclassGzipUtilities{publicstaticbooleanisGzipSupported(HttpServletRequestrequest){Stringencodings=request.getHeader(Accept-Encoding);return((encodings!=null)&&(encodings.indexOf(gzip)!=-1));}publicstaticbooleanisGzipDisabled(HttpServletRequestrequest){Stringflag=request.getParameter(disableGzip);return((flag!=null)&&(!flag.equalsIgnoreCase(false)));}publicstaticPrintWritergetGzipWriter(HttpServletResponseresponse)throwsIOException{return(newPrintWriter(newGZIPOutputStream(response.getOutputStream())));}}发送经过压缩的Web页面:LongServlet.javapublicclassLongServletextendsHttpServlet{publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{response.setContentType(text/html);//Changethedefinitionofoutdependingon//whetherornotgzipissupported.PrintWriterout;if(GzipUtilities.isGzipSupported(request)&&!GzipUtilities.isGzipDisabled(request)){out=GzipUtilities.getGzipWriter(response);response.setHeader(Content-Encoding,gzip);}else{out=response.getWriter();}发送经过压缩的Web页面:LongServlet.java(续)…out.println(docType+HTML\n+HEADTITLE+title+/TITLE/HEAD\n+BODYBGCOLOR=\#FDF5E6\\n+H1ALIGN=\CENTER\+title+/H1\n);Stringline=Blah,blah,blah,blah,blah.+Yadda,yadda,yadda,yadda.;for(inti=0;i10000;i++){out.println(line);}out.println(/BODY/HTML);out.close();}}发送经过压缩的页面:结果未经压缩(28.8Kmodem),Netscape和InternetExplorer:50seconds经过压缩(28.8Kmodem),Netscape和InternetExplorer:5seconds注意:在处理这些基准数据时要小心区分不同的浏览器类型仅在必需时才使用User-Agent否则,我们最终的代码不得不维护浏览器各个版本及其功能的表格,导致代码难以维护。检查nullHTTP1.1规范并不要求这个报头,某些浏览器允许用户禁止这个报头(如Opera),一些定制客户程序甚至有可能根本就不使用这个报头。如果要区分Netscape和InternetExplorer,请检查“MSIE”,而非“Mozilla”在这个报头的开始,Netscape和InternetExplorer都设置“Mozilla”。这是为了JavaScript的兼容性。要注意,这个报头可以伪造。如果某个客户伪造这个报头,服务器根本无从察觉。区分不同的浏览器类型(代码)publicclassBrowserInsultextendsHttpServlet{publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{response.setContentType(text/html);PrintWriterout=response.