zoukankan      html  css  js  c++  java
  • http请求报头

    客户请求的处理: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">
    " +
                    "<H1 ALIGN=CENTER>" + title + "</H1>
    " +
                    "<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);
        }
    }
    View Code

    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">
    " +
                    "<h1 align="center">" + title + "</h1>
    ");
            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()));
        }
    }
    View Code


    区分不同的浏览器类型:
    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()进行访问。

  • 相关阅读:
    20200721_34代码如何优化以及框架的运用和构建设计
    20200719_33appium应用及H5页面元素定位下
    20200709_29多线程与分布式
    day4_day4_python
    python_day3
    python第二天
    pytihon初学第一天
    移动平均线系列
    网页爬取
    十种经典排序算法
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/7793095.html
Copyright © 2011-2022 走看看