客户请求的处理:Http请求报头
创建高效servlet的关键之一,就是要了解如何操纵超文本传输协议(HypeText TransferProtocol, HTTP)。
HTTP请求报头不同于前一章的表单数据。表单数据直接来源于用户的输入,对于GET请求,这些数据是URL的一部分,对于POST请求,这些数据在单独的行中。相应的,请求报头由浏览器间接设定,并紧跟在初始的GET和POST请求行之后发送。

请求报头的读取:
HttpServletRequest的getHeader方法,使用报头名称为参数。有返回String,没有返回null。
报头名称对大小写不敏感。
尽管getHeader是读取报头的通用方式,但由于几种报头的应用太普遍,故而HttpServletRequest为它们提供了专门的访问方法:
getCookies
getCookies返回Cookie报头的内容,这些内容经分析后存储在由Cookie对象构成的数组中。
getAuthType和getRemoteUser
getAuthType和getRemoteUser方法对Authorization报头进行拆分,分解成它的各个构成部分。
getContentLength
getContentLength方法返回Content-Length报头的值(int)
getContentType
getContentType返回Content-Type报头的值(string)
getDateHeader和getIntHeader
getDateHeader和getIntHeader饭别读取指定的报头,然后分别将它们转换成Date和int值
getHeaderNames
可以用getHeaderNames方法得到一个Enumeration,枚举当前特定请求中所有的报头名称
getHeaders
大多数情况下,每个报头名称在请求中只出现一次。然而报头偶尔也可能出现多次,每次出现列出各自的值。Accept-Language就是一例子。您可以使用getHeaders获取一个Enumeration,枚举报头每次出现所对应的值
除了查找请求的报头之外,您还可以获取主请求行自身的信息,同样是使用HttpServletRequest提供的方法
getMethod
返回主请求方法
getRequestURI
返回URL中主机和端口之后,但在表单数据之前的部分
getQueryString
返回表单数据
getProtocol
getProtocol方法返回请求行的第三部分,一般为HTTP/1.0或者HTTP/1.1。
了解Http请求报头:
Accept:浏览器能处理的MIME类型。
Accept-Charset: 浏览器使用的字符串
Accept-Encoding
Accept-Language:浏览器使用的语言,如en
Authorization:访问需要用户信息的web页面的时候,用这个报头标识自己身份
Connect:标识浏览器能否处理持续性连接。Keep-Alive表示应该使用持续性连接,close表示使用旧式连接
Content-Length:
Cookie:
Host:URL中的主机名和端口号
if-Modified-Since:这个报头标明,仅当页面在指定日期之后修改的情况下,客户程序才能访问页面。如果没有更新的结果,则返回403.这个选项十分有用,因为使用它,浏览器可以缓存文档,只有他们发生更改时才通过网络重新载入。但是servlet不需要直接处理这个报头。取而代之,他们应该事先getLastModified方法,让系统自动处理修改日期。

使用getLastModified的例子:

package com.zhen.test.o2;

import com.zhen.util.ServletUtilities;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter; /**
* Created by zhen on 2017-10-10.
* Example using servlet initialization and the getLastModified method
*/
public class LottyNumbers extends HttpServlet{
private long modTime;
private int[] numbers = new int[10]; /**
* The init method is called only when the servlet is first loaded, before the first request is processed.
* @throws ServletException
*/
public void init() throws ServletException {
// Round to nearest second (i.e, 1000 milliseconds)
modTime = System.currentTimeMillis()/1000*1000;
for(int i=0; i<numbers.length; i++){
numbers[i] = randomNum();
}
} /** Return the list of numbers that init computed. */
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
String title = "Your Lottery Numbers";
out.println(ServletUtilities.headWithTitle(title) +
"<BODY BGCOLOR=\"#FDF5F6\">\n" +
"<H1 ALIGN=CENTER>" + title + "</H1>\n" +
"<B> Based ypon extensive research of astro-illogical statistical claptrap, we have chosen the " +
numbers.length + "best lottery numbers for you. </B>" +
"<OL>"
);
for(int i=0; i<numbers.length; i++) {
out.println(" <LI>" + numbers[i] + "</LI>");
}
out.println("</OL>" +
"<BODY></HTML>");
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
} /**
* The standard service method compares this date against any date specified in the If-Modified-Since request header.
* If the getLastModified date is later or if there is no
* If-Modified-Since header, the doGet method is called
* normally. But if the getLastModified date is the same or earlier, the service method sends back a 304 (Not Modified)
* response and does not call doGet. The browser should use it cached version of the page in such a case.
* @param req
* @return
*/
@Override
public long getLastModified(HttpServletRequest req) {
return (modTime);
} // A random int from 0 to 99
private int randomNum() {
return (int)(Math.random() * 100);
}
}

if-Modified-Since:
这个报头和if-Modified-Since正好相反:它规定仅当文档比指定的日期要旧时,操作才需要继续

Referer:标明web页面的URL。用于追踪请求来源
User-Agent:标识生成请求的浏览器或者其他客户程序

发送压缩页面
gzip文本压缩方案能极大减少HTML(或纯文本)页面的大小。大多数最近的浏览器都直达如何处理gzip压缩后的内容,所以,服务器对文档进行压缩,使得传输更小。
servlet首先检查Accept-Encoding报头,检查它是否包含有关gzip的项。如果支持,它使用PrintWriter封装GZIPOutputStream,并指定Content-Encoding响应报头值为gzip。如果不支持gzip,则使用正常的PrintWriter。浏览器禁用压缩可以在URL尾部加上?disableGzip

使用gzip压缩返回页面的例子:

package com.zhen.test.o3;

import com.zhen.util.GzipUtilities;
import com.zhen.util.ServletUtilities; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter; /**
* Created by zhen on 2017-11-05.
*/
public class LongServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
PrintWriter out;
if(GzipUtilities.isGzipSupported(req) && !GzipUtilities.isGzipDisabled(req)){
out = GzipUtilities.getGzipWriter(resp);
}else{
out = resp.getWriter();
}
String title = "Long Page";
out.println(ServletUtilities.headWithTitle(title) + "" +
"<body bgcolor=\"#FDF5E6\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n");
String line = "Blah, blah, blah, blah, blah. Yadda, yadda, yadda, yadda, yadda.";
for(int i = 0; i <10000; i++){
out.println(line);
}
out.println("</body></html>");
out.close();
}
} package com.zhen.util; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream; /**
* Created by zhen on 2017-11-05.
*/
public class GzipUtilities { 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"));
} public static PrintWriter getGzipWriter(HttpServletResponse response) throws IOException{
response.setHeader("Content-Encoding","gzip");
return new PrintWriter(new GZIPOutputStream(response.getOutputStream()));
}
}

区分不同的浏览器类型:
User-Agent报头标识发出的请求的具体浏览器。
注意细节:
1、仅仅在必需的时候才会使用User-Agent
2、检查是否为null
3、区分Netscape和Internet Explorer,要检查“MSIE”,而并非“Mozilla”.Netscape和Internet Explorer都在该报头的开始处列出“Mozilla”,尽管Mozilla是类Godzilla的Netscape吉祥物。这个特征是为了与javascript兼容
4、注意,该报头可以造假
根据客户的到达方式定制页面
Referer报头支出,用户单击链接到达当前页面时所处页面的位置。如果用户直接输入页面的地址。那么浏览器就不会发送Referer。
通过这个报头,可以做到:
1、创建一个工作网站,承袭链接到它的相关网站的外观感觉。
2、根据链接来自防火墙内部还是外部,更改页面的内容
3、提供相应的链接,使用户能够返回之前的页面
4、跟踪标题广告的有效性,或者记录显示您广告不同网站的点击率

标砖CGI变量的访问
存在一个有些混杂的集合,存储各种与当前请求相关的信息。有些基于http请求中的行和报头,其他来自于socket本身,还有一些取自服务器的安装参数。
servlet中CGI变量的等价物:
1、AUTH_TYPE
若提供了Authoriztion报头。这个变量给出指定的模式(basic或digest)。用request.getAuthType()来访问它。
2、CONTENT_LENGTH
调用request.getContentLength()即可访问
3、CONTENT_TYPE
调用request.getContentType()即可访问
4、DOCUMENT_ROOT
DOCUMENT_ROOT变量指定与URL http://host/对应的实际目录。用getServletContext()。getRealPath("/")对它进行访问
5、HTTP_XXX_YYY
Cookie报头成为HTTP_COOKIE, User-agent成为HTTP_USER_AGENT,Referer称为HTTP_REFERER,依次类推。servlet应该只是用request.getHeaderNames或者快捷方法
6、PATH_INFO
路径信息可以作为常规表单数据的一部分进行发送,之后用getServletContext().getRealPath进行转换。是用request.getPathInfo()访问PATH_INFO的值
7、PATH_TRANSLATED
PATH_TRANSLATED给出映射到服务器实际路径的路径信息。通过request.getPathTranslated()访问。
8、QUERY_STRING
对于get请求,这个变量以单字符串的形式给出附加的数据,这些数据依旧保持URL编码之后的状态,一般使用getParameter访问。如果您真的需要原始数据,可以通过request.getQueryString()得到它
9、REMOTE_ADDR
这个变量指出发出请求的客户机的IP地址,调用request.getRemoteAddr()对它进行访问
10、REMOTE_HOST
给出发出请求的客户机的完全限定域名,如果不能确定域名,返回ip地址。使用request.getRemoteHost()访问
11、REMOTE_USER
如果提供了Authorization报头,并经过服务器自身的解码,那么REMOTE_USER变量给出用户相关的部分。用request.getRemoteUser访问它
12、REQUEST_METHOD
通过request.getMethod()访问这个变量
13、SCRIPT_NAME
这个变量给出servlet的路径,相对于服务器的根目录。可以通过request.getServletPath()访问
14、SERVER_NAME
服务器计算机的主机名。可以用request.getServerName访问
15、SERVER_PORT
存储服务器正在侦听的端口。技术上等价于String.valueOf(request.getServerPort())
16、SERVER_PROTOCOL
标明在请求行中使用的协议名称和版本。用request.getProtocol进行访问
17、SERVER_SOFTWARE
给出web服务器的标识信息。通过getServletContext().getServletInfo()进行访问。

http请求报头的更多相关文章

  1. HTTP报头:通用报头,请求报头,响应报头和实体报头

    缓存控制优先级从高到低分别是Pragma -> Cache-Control -> Expires 报头 每一个报头都是由 [名称 + ":" + 空格 + 值 + ] ...

  2. 四种为HttpClient添加默认请求报头的解决方案

    HttpClient在Web调用中具有广泛的应用,而为它添加默认请求头是我们经常遇到的需求,本文介绍4种为HttpClient添加默认请求头的方式. 第一种方式 直接在创建的HttpClient对象的 ...

  3. 如何实现Http请求报头的自动转发[应用篇]

    如今的应用部署逐渐向微服务化发展,导致一个完整的事务往往会跨越很多的应用或服务,出于分布式链路跟踪的需要,我们往往将从上游服务获得的跟踪请求报头无脑地向下游服务进行转发.本文介绍的这个名为Header ...

  4. SpringMVC(六):@RequestMapping下使用@RequestHeader绑定请求报头的属性值、@CookieValue绑定请求中的Cookie值

    备注:我本地浏览器的报头(Request Header)信息如下: Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image ...

  5. Http请求报头设置

    1.添加一个SetHeaderValue方法: public static void SetHeaderValue(WebHeaderCollection header, string name, s ...

  6. http请求报头和响应报头(1)

    1.web端不可避免的http缓存机制,要理解缓存机制,先来了解下http的请求报文和响应报文的内容 2.请求报文  2.1请求行    请求行三部分组成:请求方法.URL以及版本协议 请求的方法有G ...

  7. HTTP请求报头及其处理

    ps:详细说明http://www.cnblogs.com/kkgreen/archive/2011/04/11/2012829.html

  8. 《HTTP协议详解》读书笔记---请求篇之消息报头

    不管是请求消息还是响应消息都包含消息报头,那么消息报头包含哪些内容?他们都代表什么含义呢?以下将带着 这些问题去学习消息报头. http消息(不管是请求消息还是响应消息)都是由开始行,消息报头(可选) ...

  9. ASP.NET Core应用针对静态文件请求的处理[3]: StaticFileMiddleware中间件如何处理针对文件请求

    我们通过<以Web的形式发布静态文件>和<条件请求与区间请求>中的实例演示,以及上面针对条件请求和区间请求的介绍,从提供的功能和特性的角度对这个名为StaticFileMidd ...

随机推荐

  1. centos6搭建redis集群搭建(单机多节点)

    一.安装redis 1.安装gcc环境 yum install gcc-c++ 2.下载源码包并解压 wget http://download.redis.io/releases/redis-3.2. ...

  2. (转)Nuts and Bolts of Applying Deep Learning

    Kevin Zakka's Blog About Nuts and Bolts of Applying Deep Learning Sep 26, 2016 This weekend was very ...

  3. 论文笔记——Rethinking the Inception Architecture for Computer Vision

    1. 论文思想 factorized convolutions and aggressive regularization. 本文给出了一些网络设计的技巧. 2. 结果 用5G的计算量和25M的参数. ...

  4. UVa 1025 城市里的间谍

    https://vjudge.net/problem/UVA-1025 题意:一个间谍要从第一个车站到第n个车站去会见另一个,在是期间有n个车站,有来回的车站,让你在时间T内时到达n,并且等车时间最短 ...

  5. python 获取格式化时间

    #!/usr/bin/python # -*- coding: UTF- -*- import time localtime = time.asctime( time.localtime(time.t ...

  6. ubuntu server 16.04(amd 64) 配置网桥,多网卡使用激活

    安装了Ubuntu16.04的server版本,结果进入系统输入ifconfig后发现,只有一个网卡enp1s0,还有一个网络回路lo,ifconfig -a 发现其实一共有四个网卡,enp1s0,e ...

  7. A_Pancers团队项目设计完善&编码测试

    1:根据OOD详细设计工作要点,修改完善团队项目系统设计说明书和详细设计说明 我们在项目真正开发与测试的过程当中发现我们的项目开发流程不是很明确,我们对于软件开发流程和功能分布做了补充和完善,并且认为 ...

  8. 《剑指offer》第二十九题(顺时针打印矩阵)

    // 面试题29:顺时针打印矩阵 // 题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. #include <iostream> void PrintMatrixInC ...

  9. 新的请求方式 fetch和axios

    参考链接:https://www.javascriptcn.com/read-5840.html axios使用文档: https://www.kancloud.cn/yunye/axios/2348 ...

  10. Java读写记事本文件

    Java中我们也会考虑读写记事本,文件读取如下: public static void main(String[] args) { try { String path="d:\\abc.tx ...