2020-0504:HTTP协议:响应消息&Response对象

357 阅读8分钟

今日内容

1. HTTP协议:响应消息
2. Response对象
3. ServletContext对象

一、HTTP协议:

* 作为服务器开发人员,我们需要获取请求消息,设置发送的响应消息。
  (浏览器会自动的解析这些响应消息,所以我们无需关心这些。)
1. 请求消息:客户端发送给服务器端的数据。
    * 数据格式
        1. 请求行
        2. 请求头
        3. 请求空行
        4. 请求体
2. 响应消息:服务器端发送给客户端的数据。
    * 数据格式
        1. 响应行
            1.组成: 协议/版本 响应的状态码 状态码的描述
                     HTTP/1.1    200             OK
                                 200             OK
                        (200状态码告诉浏览器:200状态码代表OK,响应成功)
            2.响应状态码:服务器告诉客户端浏览器本次请求和响应的状态
                1.状态码都是3位数字
                * 分类:
                    1. 1xx:服务器接收客户端消息,但没有接收完成,发送1xx状态码继续等
                       待请求消息。
                    2. 2xx:成功。代表:200
                    3. 3xx:重定向。代表:302(重定向),304(访问缓存)

                    4. 4xx:客户端错误。
                        代表404(请求路径没有对应的资源)
                        代表405:请求方式(GET/POST)没有对应的(doGet()/doPost())方法
                    5. 5xx:服务器端错误。
                        代表500:服务器内部出现异常。
                            500 – Internal Server Error
        2. 响应头
            1.格式:    头名称:值
            2.常见的响应头:
                1.Content-Type: text/html;charset=UTF-8
                  服务器告诉客户端浏览器本次响应体数据格式text/html以及编码格式charset
                  =UTF-8。
                  (是根据服务器中html页面里面定义的编码格式)
                2.Content-Length: 99
                  字节个数式
                3.Centent-disposition:服务器告诉客户端以什么格式打开响应体数据。
                    * 默认值:in-line,在当前页面内打开。
                    * attachment;filename=xxx:以附加形式打开响应体。(文件下载)
        3. 相应空行
        
        4. 响应体:传输的数据。
            
        
    * 响应的字符串格式:
        1.响应行:
            HTTP/1.1 200 OK
        2.响应头:
            Content-Type: text/html;charset=UTF-8
            Content-Length: 99
            Date: Mon, 04 May 2020 05:14:15 GMT
        3.响应空行:
        
        4.响应体:html页面
            ```
            <html>
              <head>
                <title>$Title$</title>
              </head>
              <body>
              hello,response
              </body>
            </html>
            ```

二、Response对象

    * 继承体系:
        Interface ServletResponse 
                |extends
        Interface HttpServletResponse
    * 功能:设置响应消息。
        1.设置响应行
            1.格式:HTTP/1.1 200 OK
            2.设置状态码:void setStatus(int sc)  
        2.设置响应头
            1.设置头:void setHeader(String name, String value)  
        3.设置响应体
            * 使用步骤:
                1.获取输出流
                    * 字符输出流:PrintWriter getWriter()
                    * 字节输出流:ServletOutputStream getOutputStream()
                2.使用输出流将数据输出到客户端浏览器。

2.2. 案例

    1.完成重定向
        *重定向和转发类似,也是一种资源跳转的方式。
         重定向发生在:
            A资源告诉浏览器,我没有满足你的资源,B资源有。
            A资源告诉浏览器重定向状态码:302;
            告诉B资源的路径:响应头location(B资源的路径)
        * 代码
        ```
            //访问/responseDemo1资源,会自动跳转到/responseDemo2资源。
            //1.设置状态吗为302
            resp.setStatus(302);
            //2.设置响应头location
            resp.setHeader("location", "/day0504_Response/responseDemo2");
        ```
        * 发现除了setHeader()的第二个参数外,其他都是固定的,所以Response对象提供了
          简单的重定向方式。
            void sendRedirect(String location)  
            resp.sendRedirect("/day0504_Response/responseDemo2");
        * 为了避免虚拟目录改变引起的资源丢失:动态获取虚拟目录
            String contextPath = req.getContextPath();
            resp.sendRedirect(contextPath+"/responseDemo2");
            
            
        * 重定向(redirct)的特点:
            1. 转发地址栏路径变化
            2. 转发可以访问其他站点(服务器)的资源
            3. 转发是两次请求
                不能request对象来共享数据了。
        * 转发(forward)的特点:
            1. 转发地址栏路径不变
            2. 转发只能访问当前服务器下的资源
            3. 转发是一次请求。
                意味着可以使用request对象来共享数据
        * 路径的写法
            1.路径的分类:
                1.相对路径:通过相对路径不可以确定唯一资源
                    * 如:./index.html
                    * 不以/开头,以.开头(在当前路径下)
                    * 规则:确定当前资源和目标资源之间的相对位置关系。
                    * ./:当前资源的当前目录
                    * ../:当前资源的上一级目录
                2.绝对路径:通过绝对路径可以确定唯一的资源
                    * 如:http://localhost/day0504/responseDemo1
                    * 简化省去协议,服务器ip域名和端口:/day0504/responseDemo1
                    * 可以简单的认为:以/开头的路径
                    
                    * 规则:判断定义的路径是给谁用的?判断请求从哪发出
                        * 给客户端浏览器使用:需要加虚拟目录
                            一般都是从浏览器发出的请求:请求服务器的资源。
                            重定向也要加虚拟目录。
                            建议虚拟目录动态获取:request.getContextPath()。
                        * 给服务器使用:不需要加虚拟目录
                            如:转发。是在服务器内部,通过AServlet请求BServlet。是服务
                            器内部做的一个资源跳转,这是给服务器内部使用的。(地址栏
                            没有变化)
                        
    2.服务器输出字符数据到浏览器
        * 步骤:
            1. 获取字符输出流
                PrintWriter pw = resp.getWriter();获取的流默认编码是:ISO-8859-1
            2. 输出数据
        * 乱码
            输出数据:编码
                服务器
            浏览器显示:解码
                字符集:默认的字符集GBK
        * 解决乱码:
            1.重新设置流的编码
            2.告诉浏览器服务器发送的响应体使用的编码
            3.在设置流之前设置。
            resp.setContentType("text/html;charset=GBK");
        * 详见:ResponseDemo4
        
    3.服务器输出字节数据到浏览器
        //服务器告诉浏览器:我发送的消息体编码格式是utf-8,建议浏览器也是用该编码解码
        resp.setContentType("text/html;charset=utf-8");

        //1.获取字节输出流
        ServletOutputStream sos = resp.getOutputStream();

        //2.输出数据
        //sos.write("你好".getBytes());默认的是GBK
        sos.write("你好".getBytes("utf-8"));
        
        * 详见:ResponseDemo5
        
    4.验证码
        1.本质:图片
        2.目的:防止恶意表单注册。
        * 详见CheckCodeServlet,register.html

三、ServletContext对象

1.概念:代表整个web应用(工程),可以和应用的容器(服务器)来通信
2.获取:
    1.通过request对象获取
        request.getServletContext();
    2.通过HttpServlet获取
        HttpServlet的父类GenericServlet中的方法:getServletContext() 
        一般我们写的Servlet继承了HttpServlet,所以可以直接用。
        this.getServletContext();
3.功能:
    1.获取MIME类型
        * MINE类型:在互联网通信过程中定义的一种文件数据类型
            * 格式:大类型/小类型 text/html     image/jpeg
        * 获取:通过ServletContext中的方法:
            * String getMimeType(String file)  
            
    2.域对象:共享数据的。
        1. setAttribute(String name, Object value)
        2. getAttribute(String name)
        3. removeAttribute(String name)
        * ServletContext对象域的范围:所有用户(可以看不同的的浏览器,那么就是不同用户
          的请求),所有请求的数据。
        * 生命周期:服务器启动创建,服务器关掉销毁。所以在内存中长时间存在。
        
    3.获取文件的真实/运行(服务器)路径。
            我们写了一个web项目,那么该项目会存在于两个地方。tomcat和本地工作空间,这
        两个地方各有一份。当我们用浏览器访问这个项目,肯定是找tomcat的,尽管我们目前可
        以在单机运行,但是将来这些项目一定是在远程运行的,那么就需要了解该项目真实的运
        行路径。
            1.方法:ServletContext中的方法
                String getRealPath(String path)  
            每一个项目都会对应一个配置:
            Using CATALINA_BASE:   "C:\Users\13099\.IntelliJIdea2019.3\system\tomcat\Tomcat_8_5_31_day0504_Response"
            在该目录下的Catalina\localhost\day0504_Response.xml文件中。
            
            打开该文件:有如下内容
              <Context path="/day0504_Response" docBase="E:\Idea_Project\day0504_Response\out\artifacts\day0504_Response_war_exploded" />
            那么该项目真正对应的服务器路径是:
            docBase="E:\Idea_Project\day0504_Response\out\artifacts\day0504_Response_war_exploded" />。
            找的是工作空间里面out目录下的写内容,并没有把它copy到webapps下面。此时
            我们可以找到这个目录,这个目录下的内容被发布到服务器里面了。
            
                所以ServletContextDemo5得到的b.txt的真实路劲:
            E:\Idea_Project\day0504_Response\out\artifacts\day0504_Response_war_exploded\b.txt
            
            * 详见ServletContextDemo5

四、案例

* 文件下载需求:
	1. 页面显示超链接
	2. 点击超链接后弹出下载提示框
	3. 完成图片文件下载
* 分析
    1.浏览器默认超链接指向的资源如果能够被浏览器解析,则在浏览器中展示,如果不能,
      则弹出下载提示框。
    2.任何资源都必须弹出下载提示框。
    3.使用响应头设置资源的打开方式:以附件的形式打开
        * content-disposition:attachment;filename=xxx
        
* 步骤:
    1.定义页面,编辑超链接href属性值,指向Servlet,传递请求参数:资源名称filename
    2.定义Servlet
        1.获取文件的名称
        2.使用字节输入流加载文件进内存
        3.指定response的响应头:content-disposition:attachment;filename=xxx
          设置响应头:文件MIME类型:content-type
        4.将数据写出到response输出流
	
* 问题:中文文件名
    <!--在弹出的下载提示框中:中文展示不出来-->
    <a href="/day0504_Response/downloadServlet?filename=九尾.jpg">图片1</a>
    * 解决思路:
        1.获取客户端使用的浏览器版本信息
        2.根据不同的版本信息,设置filename的编码方式不同

* 案例详见:
    package cn.itcast.web.download DownloadServlet;
    package cn.itcast.web.utils.DownLoadUtils;
    download.html;