zoukankan      html  css  js  c++  java
  • 请求和响应

    服务器处理请求的流程:

      • 服务器每次收到请求时,都会为这个请求开辟一个新的线程。
      • 服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体!
      • 服务器还会创建对象,这个对象与客户端连接在一起,它可以用来向客户端发送响应。

    一、HttpServletResponse对象

      1、发送状态码相关的方法

      ServletResponse:与协议无关的类型。

      HttpServletResponse:与协议相关的类型

    状态码:200表示成功、302表示重定向、404表示客户端错误(访问资源不存在)、500表示服务器端错误
    • sendError(int sc) :发送错误状态码,例如404,500
    • sendError(int sc,String msg):发送错误状态码,还可以带一个错误信息
    • setStatus(int sc):发送成功的状态码,可以用来发送302
    案例:
    @WebServlet(name = "AServlet" ,urlPatterns = "/Aservlet")
    public class AServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) 
          throws ServletException, IOException { response.sendError(404,"资源存在,但还发你404"); } } 
      2、响应头:Content-Type、Refresh、Location等等
    • setHeader(String name,String value):适用于单值的响应头,例如
     response.setHeader("aaa","AAA"); 
    • addHeader(String name,String value):适用于多值的响应头,例如:
     response.addHeader("aaa","ddd");
    response.addHeader("aaa","ccc");
    response.addHeader("aaa","fff"); 
    • setIntHeader(String name,int value):适用于单值的int类型的响应头,例如:
     response.setIntHeader("Content-Length",888); 
    • addIntHeader(String name,int value):适用于多值的int类型的响应头
    • setDateHeader(String name,long value):适用于单值得毫秒类型的响应头,例如:
    response.setDateHeader("expires",1000*60*60*24);//页面过期时间为24小时   
    • addDateHeader(String name,long value):适用于多值得毫秒类型的响应头
        常用setHeader(String name,String value).
    案例:
      • 发送302,设置Location头,完成临时重定向!
    /*
    * 演示重定向
    * 用户请求BServlet,然后BServlet响应302,给出Location头
    * */
    @WebServlet(name = "BServlet",urlPatterns = "/BServlet")
    public class BServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            System.out.println("BServlet");
            /*
            * 重定向:
            * 1、设置Location
            * 2、发送302状态码
            * */
            response.setHeader("Location","/CServlet");
            response.sendError(302);
        }
    }
    /*
    * 浏览器会重定向到这来
    * */
    @WebServlet(name = "CServlet",urlPatterns = "/CServlet")
    public class CServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("CServlet");
    }
    }
    // BServlet响应头

    HTTP/1.1 302 
    Location: /CServlet
    Content-Length: 0
    Date: Wed, 30 Aug 2017 01:57:17 GMT

      //BServlet请求头

    GET /BServlet HTTP/1.1
    Host: localhost:8080
    User-Agent: *****
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Cookie: Idea-e96526d7=db12919d-58f1-479a-b0f7-3104911c767b; Webstorm-2933ea9e=87a0f860-7465-47bb-8d57-4358bd45ea39; JSESSIONID=AD5DC7F501C87B36FF2186A0A1596564
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1

      //CServlet响应头

    HTTP/1.1 200 
    Content-Length: 0
    Date: Wed, 30 Aug 2017 01:57:17 GMT

      //CServlet请求头

    GET /CServlet HTTP/1.1
    Host: localhost:8080
    User-Agent: *****
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Cookie: Idea-e96526d7=db12919d-58f1-479a-b0f7-3104911c767b; Webstorm-2933ea9e=87a0f860-7465-47bb-8d57-4358bd45ea39; JSESSIONID=AD5DC7F501C87B36FF2186A0A1596564
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1

      • 定时刷新,设置Refresh头,可以理解为定时重定向。
    /*
    * 演示定时刷新
    * 设置一个Refresh,表示定时刷新
    * */
    @WebServlet(name = "DServlet",urlPatterns = "/DServlet")
    public class DServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            /*
            * 下面是用来发送响应体
            * */
            PrintWriter writer = response.getWriter();
            writer.print("欢迎xxx登陆!5秒钟后会自动跳转到主页!乱码来的");
            //设置名为Refresh的响应头
            response.setHeader("Refresh","5;URL=/EServlet");
        }
    }
      • 禁止浏览器缓存:Cache-Control、pragma、expires
    /*
    * 禁用浏览器缓存
    * */
    @WebServlet(name = "FServlet",urlPatterns = "/FServlet")
    public class FServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setHeader("Cache-Control","no-cache");
            response.setHeader("Pragma","no-cache");
            response.setDateHeader("Expires",-1);
        }
    }
      • <meta>标签可以替代响应头:<meta http-equiv="Content-Type" content="text/html";charset=UTF-8>
    3、响应体:通常是html、也可以是图片
      response的两个流:
      • ServletOutputStream,用来向客户端发送字节数据, ServletOutputStream out = response.getOutputStream(); 
      • PrintWriter,用来向客户端发送字符数据,需要设置编码, PrintWriter writer = respones.getWriter(); 
      • 两个流不能同时使用。
    案例:
    使用PrintWriter发送字符数据
    使用ServletOutputStream发送字节数据(图片)
    重定向:设置302,设置Location,其中变化的只有Location,所以Java提供了一个快捷方法,完成重定向。
    sendRedirect(String location)方法
     response.sendRedirect("http://www.baidu.com"); 
    二、HttpServletRequest对象
      请求协议中的数据都可以通过request对象来获取,request封装了客户端所有的请求数据,GET无请求体。

      1、获取常用信息

      • 获取客户端IP,案例:封IP,request.getRemoteAddr();
      • 请求方式,request.getMethod(),POST或GET

      2、获取请求头

      • String getHeader(String name):适用于单值头
      • int getIntHeader(String name):适用于单值int类型的请求头
      • long getDateHeader(String name):适用于单值毫秒类型的请求头
      • Enumeration<String> getHeaders(String name):适用于多值请求头

      案例:

      • 通过User-Agent识别用户浏览器类型
     1 @WebServlet(name = "AServlet",urlPatterns = "/AServlet")
     2 public class AServlet extends HttpServlet {
     3     protected void doGet(HttpServletRequest request, HttpServletResponse response)
     4             throws ServletException, IOException {
     5         String addr = request.getRemoteAddr();
     6         System.out.println("IP:"+addr);
     7         System.out.println("METHOD:"+request.getMethod());
     8         String userAgent = request.getHeader("User-Agent");
     9 //        System.out.println(userAgent);
    10        // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
    11         //是否包含Chrome,如果包含,说明用户使用的是google浏览器
    12         if(userAgent.toLowerCase().contains("chrome")){
    13             System.out.println("您好:"+addr+",您用的是谷歌");
    14         }else if (userAgent.toLowerCase().contains("firefox")){
    15             System.out.println("您好:"+addr+",您用的是火狐");
    16         }
    17     }
      • 防盗链:如果请求不是通过本站的超链接发出的,发送错误状态码404。Referer这个请求头表示请求的来源。
    @WebServlet(name = "BServlet",urlPatterns = "/BServlet")
    public class BServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            /*
            * 使用Referer请求头,来防盗链
            * 直接在地址栏输入,则Referer头值为null
            * */
            String referer = request.getHeader("Referer");
            System.out.println(referer);
            if (referer == null || !referer.contains("localhost")){
                response.sendRedirect("http://www.baidu.com");
            }else {
                System.out.println("hello");
            }
        }
    }

      3、获取请求URL

        http://localhost:8080/day10_2/AServlet?username=xx&password=yyy

    • String getScheme():获取协议,http
    • String getServerName():获取服务器名,localhost
    • String getServerPost():获取服务器端口,8080
    • String getContextPath():获取项目名, /day10_2
    • String getServletPath():获取Servlet路径, /AServlet
    • String getQueryString():获取参数部分,即问号后面的部分,username=xx&password=yyy
    • String getRequestURI():获取请求URI,等于项目名+Servlet路径,/day10_2/AServlet
    • String getRequestURL():获取请求URL,等于不包含参数的整个请求路径,http://localhost:8080/day10_2/AServlet

      4、获取请求参数:请求参数:请求参数是由客户端发送给服务的,有可能是在请求体中(POST),也有可能是在URL之后(GET)。

    • String getParameter(String name):获取指定名称的请求参数值,适用于单值请求参数
    • String[] getParamerValues(String name):获取指定名称的请求参数值,适用于多值请求参数
    • Enumeration<String> getParameterName():获取所有请求参数名称
    • Map<String,String[]> getParameterMap():获取所有请求参数,其中key为参数名,value为参数值。
    • 案例:超链接参数
    • 案例:表单数据
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6 </head>
     7 <body>
     8 <h1>测试请求参数</h1>
     9 <a href="/AServlet?xxx=XXX&yyy=YYY">点击这里</a>
    10 <hr/>
    11 <form action="/AServlet" method="POST">
    12     用户名:<input type="text" name="username"/><br/>
    13     密码:<input type="password" name="password"/><br/>
    14     爱好:<input type="checkbox" name="hobby" value="dq"/>打球
    15     <input type="checkbox" name="hobby" value="ms"/>美食
    16     <input type="checkbox" name="hobby" value="ks"/>看书
    17     <br/>
    18     <input type="submit" value="提交"/>
    19 </form>
    20 </body>
    21 </html>
     1 /*
     2 * 演示request获取请求参数!
     3 * */
     4 @WebServlet(name = "AServlet",urlPatterns = "/AServlet")
     5 public class AServlet extends HttpServlet {
     6     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     7         String username = request.getParameter("username");
     8         String password = request.getParameter("password");
     9         String[] hobby = request.getParameterValues("hobby");
    10         System.out.println(username+","+password+","+ Arrays.toString(hobby));
    11         /*
    12         * 测试获取所有请求参数的名称
    13         * */
    14         Enumeration names = request.getParameterNames();
    15         while (names.hasMoreElements()) {
    16             System.out.println(names.nextElement());
    17         }
    18         /*
    19         * 获取所有请求参数,封装到Map中
    20         * */
    21         Map<String,String[]> map = request.getParameterMap();
    22         for (String name : map.keySet()) {
    23             String[] values = map.get(name);        System.out.println(name+"="+Arrays.toString(values));
    24         }
    25         System.out.println("hello");
    26     }
    27     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    28         System.out.println("GET:"+request.getParameter("xxx"));
    29         System.out.println("GET:"+request.getParameter("yyy"));
    30     }
    31 }

      5、请求转发和请求包含:

        RequestDispatcher rd = request.getRequestDispatchet("/MyServlet"); 使用request获取RequestDisapatcher对象,方法的参数是被转发或包含的Servlet的Servlet路径      

    • 请求转发:rd.forward(request,response);
    • 请求包含:rd.include(request,response);

        有时一个请求需要多个Servlet协作才能完成,所以需要在一个Servlet跳到另一个Servlet!

      • 一个请求跨多个Servlet,需要使用转发和包含。
      • 请求转发:由下一个Servlet完成响应体,当前Servlet可以设置响应头(留头不留体);
      • 请求包含:由两个Servlet共同完成响应体(都留)。
      • 无论是请求转发还是请求包含,都在一个请求范围内,使用同一request和response。

      6、request域

          Servlet中三大域对象:request、session、application,都有如下方法

      • void setAttribute(String name,Object value)
      • Object getAttribute(String name)
      • void removeAttribute(String name)
      • 同一个请求范围内使用request.setAttribute()、request.getAttribute()来传值,前一个Servlet调用setAttribute()保存值,后一个Servlet调用getAttribute()获取

        

      7、请求转发和重定向的区别

      • 请求转发是一个请求一个响应,而重定向是两个请求两次响应
      • 请求转发地址栏不变化,而重定向会显示后一个请求的地址
      • 请求转发只能转发到本项目其他Servlet,而重定向不止重定向到本项目的其他Servlet,还能定向到其他项目
      • 请求转发是服务器端行为,只需给出转发的Servlet路径,而重定向需要给出requestURI,即包含项目名。
      • 请求转发和重定向效率是转发高,因为是一个请求。
        • 需要地址栏变化,那么必须重定向
        • 需要在下一个Servlet中获取request域中的数据,必须要使用转发。
    /*
    * 演示请求转发和包含
    * 注意在一个Tomcat中不能有name、urlPatterns名称相同的情况,否则抛异常
    * */
    @WebServlet(name = "OneServlet",urlPatterns = "/OneServlet")
    public class OneServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            System.out.println("OneServlet");
            response.setHeader("aaa","AAA");//设置响应头
          /*
          * 向request域中添加一个属性
          * */
         request.setAttribute("username","zhangsan")
         response.getWriter().print("hello OneServlet");//设置响应体,包含时显示,转发时不显示 request.getRequestDispatcher("/TwoServlet").include(request,response);//请求包含
          //等同于调用TwoServlet的service()方法
          //request.getRequestDispatcher("/TwoServlet").forward(request,response);//请求转发
      } 
    }
    @WebServlet(name = "IncludeTwoServlet",urlPatterns = "/include/TwoServlet")
    public class TwoServlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
         System.out.println(request.getAttribute("username"));
         System.out.println("TwoServlet...");
            response.getWriter().print("hello TwoServlet");//设置响应体
        }
    }

    三、编码

      常见字符编码:ISO-8889-1(不支持中文),gbk(系统默认编码,中国的国标码),utf-8(万国码,支持全世界的编码)

    1、响应编码

    • 当使用response.getWriter()来向客户端发送字符数据时,如果在之前没有设置编码,那么默认使用iso,因为iso不支持中文,一定乱码;
    • 在使用response.getWriter()之前可以使用response.setCharacterEncoding()来设置字符流的编码为gbk或utf-8,当然我们通常选择utf-8,这样发送出去的字符都使用了设置的编码方式。
    • 在使用response.getWriter()之前可以使用response.setHeader("Content-type","text/html;charset=utf-8")来设置响应头,通知浏览器这边使用的是utf-8,浏览器通过Content-Type头知道,浏览器也使用utf-8。
    • setHeader("Content-type","text/html;charset=utf-8")的快捷方法是:setContentType("text/html;charset=utf-8")。

    2、请求编码

    • 客户端发送给服务器的请求参数是什么编码:客户端首先打开一个页面,然后再页面中提交表单或点击超链接,在请求这个页面时,服务器响应的编码是什么,那么客户端发送请求时的编码就是什么
    • 服务器端默认使用什么编码来解码参数:服务器端默认ISO-8859-1来解码,一定出现乱码。
    • 请求编码处理分为两种:GET、POST,GET请求参数不在请求体中,而POST请求参数在请求体中,所有他们的处理方式是不同的!
    • GET请求编码处理:
      • String username = new String(request.getParameter("iso-8859-1","utf-8"));
      • 在server.xml中配置URIEncoding=utf-8
    • POST请求编码处理:
      • String username = new String(request.getParameter("iso-8859-1","utf-8"));
      • 在获取参数之前调用request.setCharacterEncoding(“utf-8”);

    3、URL编码

      表单的类型:Content-Type: application/x-www-form-urlencoded,就是把作为转换成%后面跟随两位的16进制。

      客户端和服务器之间传递中文时需要把它转换成网络适合的方式。

    • 它不是字符编码
    • 它是用来在客户端与服务器之间传递参数用的一种方式。
    • URL编码需要先知道一种字符编码,把字符串解码后,得到byte[],然后把小于0的字节+256,再转换成16进制,前面添加一个%。
    • POST请求默认使用URL编码,Tomcat会自动使用URL解码。
    • URL编码:String username = URLEncoder.encode(username,"utf-8");
    • URL解码:String username = URLEncoder.decode(username,"utf-8");

      我们需把链接中的中文参数,使用url来编码,使用jsp,因为HTML不能给出Java代码。

    4、路径

    • web.xml中<url-pattern>路径(叫它Servlet路径)
      • 要么以“*”开头,要么以“/”开头
    • 转发和包含路径
      • 以“/”开头:相对当前项目路径,例如:http://localhost:8080/项目名/
      • 不以“*”开头:相对当前Servlet路径。
    • 重定向路径(客户端路径)
      • 以“/”开头:相对于当前主机,例如:http://localhost:8080/,所以需要自己手动添加项目名
    • 页面中超链接和表单路径
      • 与重定向相同,都是客户端路径,需要添加项目名
    • ServletContext获取资源路径
      • 相对当前项目目录,即当前index.jsp所在目录
    • ClassLoader获取资源路径
      • 相对classes目录
    • Class获取资源路径
      • 以“/”开头相对classes目录
      • 不以“/”开头相对当前.class文件所在目录。
  • 相关阅读:
    API接口智能化测试探索与实践
    程序员的社会地位
    程序员五六年能存100万,你说你焦虑个啥!!!
    苹果公司宣布:公司内部的员工有权讨论自己的工作条件和薪酬
    男子股票账户突然多了一个亿!结果……
    你选择双休还是单休?
    PAL制式和NTSC制式的定义及区别(转)
    javascript入门系列演示·三种弹出对话框的用法实例(转)
    sink相关
    Ubuntu下安装gsteditor
  • 原文地址:https://www.cnblogs.com/gdwkong/p/7623620.html
Copyright © 2011-2022 走看看