Response&Request

作者: 明天你好向前奔跑 | 来源:发表于2017-05-26 16:41 被阅读0次

    Response&Request

    一、介绍

    Web服务器每收到一次http请求,针对每一个请求,都会创建一个代表请求的request对象和
    一个代表响应的response对象。Response其实就是响应客户端请求的对象。它可以用来给客户端写数据。
    

    二、作用

    1 : 写响应行

    setStatus(int sc) : 设置状态码
    

    2 : 写响应头

    **sendRedirect(String location)** : 请求重定向 
    setHeader(String name,String value) : 设置响应头信息
    
        // 告知客户端不缓存
    
        response.setHeader("pragma","no-cache");
        response.setHeader("cache-control","no-cache");
        response.setDateHeader("expires",0); 
    
        // 设置多少秒后刷新到指定路径的页面
        response.setHeader("refresh","count;url");
    

    3 : 写响应体

    **getWriter()** : 获取当前response对象的字符输出流
    getOutputStream() : 字节输出流
    

    三、解决中文乱码问题

    因为服务器响应默认写出编码是 ISO-8859-1 , 与客户端解析的编码不一致 , 会导致中文乱码。
    
    解决方案一:
    
    //告诉服务器Tomcat以utf-8编码写出去
    response.setCharacterEncoding("utf-8"); 
    
    //告诉客户端(浏览器)以utf-8编码解析相应回去的内容
    response.setHeader("Content-Type", "text/html;charset=utf-8");
    
    
    解决方案二:
    
    //这种方法封装了上面两个方法,包含了上面两个方法的意思
    response.setContentType("text/html;charset=utf-8");
    

    Request

    一、介绍

    Request是代表客户端请求的一个对象,用于对请求进行操作的对象。

    二、作用

    下面以在http://localhost:8080/WebTest/index.html的提交表单测试以下方法

    1 : 存 | 取数据

    request.setAttribute(name,value) 
    request.getAttribute(name)
    

    2 : 获取请求消息行信息

    **request.getContextPath() : 获取当前项目的路径
    request.getRequestURL() : 获取    
    request.getRequestURI()
    
    request.getMethod() : 获取请求提交的方式
    request.getProtacal() : 获取请求使用的协议版本
    request.getremoteHost() : 获取访问的地址   
        ......
    
    
    测试:
    
    // Request获取消息行信息的方法:
        
    System.out.println(request.getContextPath());       /WebTest
    System.out.println(request.getMethod());            POST
    System.out.println(request.getRequestURL());        http://localhost:8080/WebTest/demo
    
    System.out.println(request.getRequestURI());        /WebTest/demo
    System.out.println("=========================");
    
    getQueryString()只能获得拼在地址栏get方式提交的数据
    System.out.println(request.getQueryString());       username=jerry&password=123&password=123
    
    System.out.println(request.getProtocol());          HTTP/1.1
    System.out.println(request.getRemoteAddr());        0:0:0:0:0:0:0:1
    System.out.println(request.getRemoteHost());        0:0:0:0:0:0:0:1
    System.out.println(request.getRemoteUser());        null
    

    3 : 获取请求消息头信息

    **request.getHeader(name) : 获取指定消息头的信息
    request.getHeaderNames(name) : 获取指定属性名的所有消息头,返回Enumeration枚举项数组
    request.getHeaders(name) : 获取消息头字段为name的所有消息头。返回Enumeration枚举项
    -------------------------------------------
    request.getDateHeader()
    request.getIntHeader()
    
    
    // Request获取消息头信息的方法:
    
    // 获取单个信息头的值:request.getHeader(name)
    System.out.println(request.getHeader("User-Agent"));
    System.out.println("-----------------------------");
    结果:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3013.3 Safari/537.36  
    
    
    //获取消息头为指定名称的多个值
    //request.getHeaders(name)
    
    // 获取所有的信息头的名称:request.getHeaderNames()
    Enumeration<String> names = request.getHeaderNames();
    while (names.hasMoreElements()) {
        // 遍历获取每一个消息头名称:
        String name = (String) names.nextElement();
        // 获取每一个信息头对应的值:
        String header = request.getHeader(name);
        System.out.println(name + " : " + header);
    }   
    
    测试结果.png

    4 : 获取请求提交的参数的信息

    **request.getParameter(name) : 获得参数名为name的单个参数的值
    request.getParameterNames() : 获得提交数据的所有参数名,返回Enumeration对象
    **request.getParameterMap : 将请求消息的所有参数的名称和值存放入一个map集合中,并返回map集合
    ---------------------------------------------------------
    request.getParameterValues(name) : 获得参数名为name的所有参数的值,返回String数组
    
    
    测试:
    
        // Request获取参数的方法:
    
        // 获取单个参数:request.getParameter(name)
        System.out.println(request.getParameter("username"));
        System.out.println("=============================");
        
        // 获取参数名相同的多个参数值:
        String[] values = request.getParameterValues("password");
        System.out.println(Arrays.toString(values));
        System.out.println("=============================");
        
        // 获取所有参数名
        Enumeration<String> names = request.getParameterNames();
        while (names.hasMoreElements()) {
            // 获取每一个参数名
            String name = (String) names.nextElement();
            // 获取每一个参数名对应的值
            String value = request.getParameter(name);
            System.out.println(name + " : " + value);
        }
        System.out.println("=============================");
    
        // 获取所有的参数与参数值的map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        // 增强for遍历map集合,输出参数名和他的值
        for (Entry<String, String[]> set : parameterMap.entrySet()) {
            String key = set.getKey();
            String[] strings = set.getValue();
    
            if (strings.length == 1) {  
                System.out.println(key + "---" + strings[0]);
            } else {
                System.out.println(key + "---" + Arrays.toString(strings));
            }
        }       
    
    测试结果.png

    5 : request对象处理中文乱码问题

    客户端提交数据有时候会有中文,而在客户端(如浏览器)的HTML页面默认以UTF-8的编码进行解码,将提交的数据
    解析成二进制,但是当服务器(Tomcat)接收到提交的数据后,服务器会以默认的编码:ISO-8859-1编码,因此会
    出现中文乱码现象。处理乱码GET请求和POST请求的处理方式如下:
    
    • POST请求提交中文到服务器

        请求对象中告诉服务器以UTF-8进行编码:
        request.setCharacterEncoding("UTF-8")  
      
    • GET请求

        服务器通过getParameter(name)获得的参数经过ISO-8859-1编码,将它重新变为byte字节数组,然后UTF-8的格式重新编码
      
        例如:
            filename = new String(filename.getBytes("ISO-8859-1"),"UTF-8");
      

    还是以上面的页面进行测试:

    Get请求.png
    在姓名输入框中输入:林志玲
    在没有进行中文处理之前,点击确定显示乱码
    
    GET请求结果.png
    GET方式处理乱码:
        
    //获取要处理的参数username
    System.out.println(request.getMethod());
    String username = request.getParameter("username");
    //将以ISO-8859-1编码的username参数重新以UTF-8编码
    username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
    System.out.println(username);
    System.out.println("=============================");
    
    GET中文2乱码处理后.png
    POST方式处理乱码:
    
    //告诉服务器以指定格式的编码进行编码
    request.setCharacterEncoding("UTF-8");
    
    System.out.println(request.getMethod());
    System.out.println(request.getParameter("username"));  
    
    POST请求处理后.png

    三、作用域

    request对象是在服务器接收到请求时,在service()方法调用之前就创建了,在服务器对客户端做出响应之后销毁。
    
    • 生命周期

      • 创建:
        • 产生一个请求时创建request对象
      • 销毁
        • 服务器对客户端做出响应后

    正是由于request对象生命周期,也决定了request对象的作用域只能在当次请求有效。
    因此它与ServletContext不同,ServletContext的作用域在当前项目下都有效。

    四、页面跳转(重定向与请求转发)

    1、 重定向

    由response对象处理,响应给客户端,让它跳转页面
    
    原始版本:
    
        //告诉客户端要进行重定向操作
        response.setHeader(302);
        //告诉客户端要跳转的页面
        response.setHeader("Location",url);
    
    封装后:
        response.sendRedirect(url);
    
    重定向请求图解

    2、请求转发

    由request对象处理。
    
    请求转发:
    request.getRequestDispatcher(url).forward(ServletRequest req,ServletResponse resp);
    
    请求包含:(相当于把后面那个页面的代码追加到前面这个页面)
    request.getRequestDispatcher(url).include(ServletRequest req,ServletResponse resp);
    
    请求转发的请求图解

    五、案例

    1:下载服务器文件位置在Resource中的资源

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    
        // System.out.println(this.getServletContext().getRealPath(""));
        // D:\Develop\apache-tomcat-7.0.52\wtpwebapps\day16_DownLoadDemo
        // 默认访问的是服务器当前项目的根目录
        // 1.点击下载发送请求,就会将其要下载的文件路径发送过来,使用request获取要下载资源的文件名
        String filename = request.getParameter("filename");
        System.out.println("文件名处理前:"+filename);
        // 1.1 获取要下载文件的类型,现在浏览器会帮忙处理 
        String mimeType = this.getServletContext().getMimeType(filename);
        response.setHeader("Content-Type", mimeType);
        System.out.println(mimeType);
        request.setCharacterEncoding("UTF-8");
        //让服务器与客户端使用的编码一致
        response.setContentType("UTF-8");
        
        // 2.下载文件
        // 获取到的filename参数是通过GET方式发送的,为了防止中文乱码
        filename = new String(filename.getBytes("ISO-8859-1"), "utf-8");
        System.out.println("文件名处理后:"+filename);
    
        // 通过资源的相对路径获得该资源的全路径
        String realPath = this.getServletContext().getRealPath("Resource/" + filename);
    
        // 为了在下载时能够使中文能正确在浏览器的URL栏正确显示,需要对filename再做一次URL编码处理
        // 获取浏览器的信息
        String agent = request.getHeader("User-Agent");
        System.out.println(agent);
        // Firefox使用的是Base64的编码,而IE和谷歌等下载中文文件时使用的是URL编码
        if (agent.toLowerCase().contains("firefox")) {
            filename = base64EncodeFileName(filename);
        } else {
            filename = URLEncoder.encode(filename,"UTF-8");
        }
        
        //设置下载时的确认框Content-Dispositon
        response.setHeader("Content-Dispositon", "attachment;filename="+filename);
        //获取输入流
        InputStream is = new FileInputStream(realPath);
        //获取输出流
        ServletOutputStream os = response.getOutputStream();
        
        int len = 0;
        byte[] bys = new byte[1024];
        
        while ((len = is.read(bys)) != -1) {
            os.write(bys, 0, len);
        }
        
        os.close();
        is.close();
    }
    
    public static String base64EncodeFileName(String fileName) {
        BASE64Encoder base64Encoder = new BASE64Encoder();
        try {
            return "=?UTF-8?B?" + new String(base64Encoder.encode(fileName.getBytes("UTF-8"))) + "?=";
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
    文件下载案例.png

    2:使用验证码工具包完成验证码更换功能

    Servlet响应类:
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //导入验证码工具jar包,ValidateCode.jar
        
        //创建获取验证码对象
        ValidateCode validateCode = new ValidateCode(120, 40, 4, 12);
        
        //获取验证码,可以用于与用户校对    
        //String code = validateCode.getCode();
        
        //谁发送请求过来,就将验证码写给谁
        validateCode.write(response.getOutputStream());
    }
    
    Html页面:

    难点:

    • 除了每次访问页面会发送一次请求,src和href也会发送一次请求,他们发送请求到Servlet,服务器对其做出响应。

    • 为了实现点击验证码图片能够完成更换验证码功能,为其添加了onclick点击事件,但会发现点击一次之后就不再变化了,这是因为浏览器缓存了验证码图片。在请求的地址后面添加参数,让其每次的请求地址都不同,这样就可以避免这个问题。

    • 在后面添加a标签:看不清换一张。如果直接在a标签中绑定点击事件href即使不填,也会跳到一个新的空白页面。为了让其不跳转页面,href="javascirpt:changeCode()"。javascript的意思是告诉html页面href后面跟的不是url地址,让其直接调用changeCode()方法

        </div>
        <div class="col-sm-2">
        ![](code)
        <a href="javascript:changeCode()">看不清,换一张</a>
        </div>
        
        <script type="text/javascript">
            function changeCode() {
                //获取验证码图片元素
                var image = document.getElementById("img01");
                //让该验证码图片的地址改变,发送请求道Servlet(一般href和src都会发送一次请求)
                //为了防止浏览器读取缓存,为了让其网址每次都不同,加上new Date()作为参数
                image.src="code?time="+new Date();
            }
        </script>
      
    验证码案例.png

    相关文章

      网友评论

        本文标题:Response&Request

        本文链接:https://www.haomeiwen.com/subject/lpsxfxtx.html