客户请求的处理:HTTP请求报头
创建高效的servlet的关键之一,就是要了解如何操纵HTTP超文本传输协议。
请求报头是指浏览器发送到服务器的HTTP信息,它不同于前面提到的表单数据,它是有浏览器间接设定的的。
一个典型的HTTP请求如下,它可能是用户向位于http://www.somebookstore.com/servlet/Search的servlet提交书籍搜索时产生的:
GET /servlet/Search?keywords=servlets+jsp HTTP/1.1
Accept: image/gif, image/jpg, */*
Accept-Encoding: gzip
Connection: Keep-Alive
Cookie: userID=id456578
Host: www.somebookstore.com
Referer: http://www.somebookstore.com/findbooks.html
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
请求报头的内容是关于这个请求的一些信息。
报头名称----报头的值
5.1 请求报头的读取
只需调用HttpServletRequest的getHeader方法即可返回当前请求指定的报头(String类型的或者null)
如:request.getHeader("connection"),即得到connection报头的内容
尽管getHeader是读取报头的通用方式,但由于几种报头使用很普遍,HttpServletRequest提供了专门的访问方法:
getCookies
返回Cookie报头的内容,存储在由Cookie对象构成的数组中。
getAuthType 和getRemoteUser
对Authorization报头进行拆分,分解成各个组成部分
getContentLength
返回Content-Length报头的值(int类型)
getContentType
返回Content-Type报头的值,(String类型)
getDateHeader 和getIntHeader
读取指定的报头,并转化为Date和int值
getHeaderNames
得到一个Enumeration,枚举当前请求中所有的报头名称
getHeaders
对于一个出现多次的报头名称,用此方法得到一个Enumeration,枚举这个报头所有的值
getMethod
返回主请求方法
getRequestURI
返回请求的这个URL中主机端口之后,表单数据之前的部分,例如:http://randomhost.com/servlet/search.BookSearch?subject=jsp
返回/servlet/search.BookSearch
getQueryString
返回表单数据,同样以上述URL为例,返回subject=jsp
getProtocol
返回HTTP协议的版本
5.2 示例:创建一个表格,读取它所接收到的所有报头以及报头的值
调用request.getHeaderNames得到所有报头名字的一个Enumeration,然后迭代。
1 package coreservlets;
2
3 import java.io.*;
4 import javax.servlet.*;
5 import javax.servlet.http.*;
6 import java.util.*;
7
8
9 public class ShowRequestHeaders extends HttpServlet {//servlet继承自HttpServlet
10 public void doGet(HttpServletRequest request,
11 HttpServletResponse response)//doGet的两个参数
12 throws ServletException, IOException {
13 response.setContentType("text/html");//输出的格式
14 PrintWriter out = response.getWriter();//输出out
15 String title = "Servlet Example: Showing Request Headers";
16 String docType =
17 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +
18 "Transitional//EN\">\n";
19 out.println(docType +
20 "<HTML>\n" +
21 "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" +
22 "<BODY BGCOLOR=\"#FDF5E6\">\n" +
23 "<H1 ALIGN=\"CENTER\">" + title + "</H1>\n" +
24 "<B>Request Method: </B>" +
25 request.getMethod() + "<BR>\n" +//请求方法
26 "<B>Request URI: </B>" +//URL
27 request.getRequestURI() + "<BR>\n" +
28 "<B>Request Protocol: </B>" +//协议版本
29 request.getProtocol() + "<BR><BR>\n" +
30 "<TABLE BORDER=1 ALIGN=\"CENTER\">\n" +
31 "<TR BGCOLOR=\"#FFAD00\">\n" +
32 "<TH>Header Name<TH>Header Value");
33 Enumeration headerNames = request.getHeaderNames();//全部报头的枚举
34 while(headerNames.hasMoreElements()) {
35 String headerName = (String)headerNames.nextElement();//每一个报头名
36 out.println("<TR><TD>" + headerName);
37 out.println(" <TD>" + request.getHeader(headerName));//request.getHeader(headerName),每个报头的值
38 }
39 out.println("</TABLE>\n</BODY></HTML>");
40 }
41
42
43 //在doPost里调用doGet
44 public void doPost(HttpServletRequest request,
45 HttpServletResponse response)
46 throws ServletException, IOException {
47 doGet(request, response);
48 }
49 }
去请求这个servlet:http://localhost:8080/Servlet/servlet/ShowRequestHeaders
5.3 了解HTTP1.1 请求报头
了解HTTP1.1最常见的几种报头的意义
报头名:
Accept 浏览器或者其他客户程序能处理的MIME类型
Accept-Charset 浏览器可以使用的字符集
Accept-Encoding 编码类型
Accept-Language 语言
Authorization 在访问密码保护的页面时,客户用这个报头表示自己的身份
Connection 客户能否处理连续性的HTTP连接
Content-Length 只是用于POST请求,给出POST数据的大小
Cookie 向服务器返回cookie,这些cookie是之前由服务器发送给浏览器的
Host 原始url的主机名和端口号
If-Modified-Since 仅当页面在指定日期之后发生更改的情况下,客户程序才希望获取该页面
If-Unmodified-Since 与上相反
Referer 表明引用web页面的url,即你是从哪个页面链接到这个页面来的
User-Agent 标识生成请求的浏览器或其他客户程序,可以根据这个为不同的浏览器返回不同的内容
5.4 示例:发送压缩的web页面---Accept-Encoding
Accept-Encoding报头中指出了当前浏览器是否支持gzip编码,对于支持gzip编码的浏览器而言,发送压缩的web页面可以大大提高性能,压缩页面在网络上传输流量更小,在浏览器端在自动解压缩并以正常方式生成结果。
对于支持gzip的情况,使用GZIPOutputStream来输出即可
if (GzipUtilities.isGzipSupported(request) &&
!GzipUtilities.isGzipDisabled(request)) {
out = GzipUtilities.getGzipWriter(response);//只是输出流不一样而已
response.setHeader("Content-Encoding", "gzip");
} else {
out = response.getWriter();
}
判断是否支持gzip的方法:
public static boolean isGzipSupported
(HttpServletRequest request) {
String encodings = request.getHeader("Accept-Encoding");
return((encodings != null) &&
(encodings.indexOf("gzip") != -1));
}
public static boolean isGzipDisabled
(HttpServletRequest request) {
String flag = request.getParameter("disableGzip");
return((flag != null) && (!flag.equalsIgnoreCase("false")));
}
5.5 示例:区分不同的浏览器类型---User-Agent
可以从报头User-Agent中得到浏览器类型的相关信息,由此可为不同的浏览器返回不同的内容:
String userAgent = request.getHeader("User-Agent");
if ((userAgent != null) &&
(userAgent.indexOf("MSIE") != -1)) {
title = "Microsoft Minion";
message = "Welcome, O spineless slave to the " +
"mighty empire.";
} else {
title = "Hopeless Netscape Rebel";
message = "Enjoy it while you can. " +
"You <I>will</I> be assimilated!";
}
5.6 示例:根据客户的到达方式定制页面 ---Referer
Referer报头指出,用户单击连接到达当前页面时所处页面的位置。如果用户直接输入页面地址,那么浏览器就不会发送Referer,request.getHeader("Referer")为null。
你可以这样来得到refer的内容:
String referer = request.getHeader("Referer");//请求这个servlet之前所在的页面的url
根据这个url可以来判断这个url是否包含某些字符,以此来做不同的显示。
if (contains(referer, "JRun")) {
imageName = "jrun-powered.gif";
} else if (contains(referer, "Resin")) {
imageName = "resin-powered.gif";
} else {
imageName = "tomcat-powered.gif";
}
从而在后面的程序中根据请求的来源(是从哪个页面链接过来的)显示不同的图片。
5.7 标准CGI变量的访问
servlet中CGI变量的等价物,了解
这一章主要讲述了什么是http请求报头,以及几个常见的报头的用法,这几个报头的应用