0%

HTTP-复习

HTTP-复习

概述

  • Hyper Text Transfer Protocol 超文本传输协议
    • 传输协议:定义了客户端和服务器通信时,发送数据的格式
  • 特点:
    1. 基于TCP/IP的高级协议
    2. 默认端口号:80
    3. 基于请求/响应模型的:一次请求对应一次响应
    4. 无状态的:每次请求之间相互独立,不能交互数据
  • 历史版本:
    • 1.0:每次请求响应都会建立连接
    • 1.1:复用连接

请求

  1. 请求行

    请求方式 请求url 请求协议/版本

    GET /login.html HTTP/1.1

    • 请求方式:
      • HTTP协议有7种请求方式,常用的有2种
        • GET:
          1. 请求参数在请求行中,在url后
          2. 请求的url长度有限制
          3. 不太安全
        • POST:
          1. 请求参数在请求体中
          2. 请求长度无限制
          3. 相对安全
  2. 请求头-客户端浏览器告诉服务器一些信息

    请求头名称:请求头值

    Host:localhost

    • 常见请求头:
      • User-Agent:浏览器告诉服务器,访问时使用的浏览器版本信息(可以在服务器获取该头信息,解决浏览器的兼容性问题)
      • Referer:http://localhost/login.html(告诉服务器,当前请求从哪里来)
        • 作用:
          1. 防盗链
          2. 统计工作
  3. 请求空行

    空行

  4. 请求体(正文)

    • 封装POST请求消息的请求参数的

## Request

Request-原理

  1. tomcat服务器会根据请求url中的资源路径,创建对应的ServletDemo的对象
  2. tomcat服务器,会创建request和response对象,request对象中封装请求消息数据
  3. tomcat将request和response两个对象传递给service方法,并且调用service方法
  4. 程序员可以通过request获取请求消息数据,通过response对象设置响应消息数据
  5. 服务器在给浏览器做出响应前,会从response对象中获取响应消息数据
  1. request和response对象是由服务器创建的,我们来使用它们
  2. request对象是来获取请求消息,response对象是来设置响应消息的

Request-对象继承体系结构

  • ServletRequest -- 接口
  • HttpServletRequest(继承ServletRequest) -- 接口
  • org.apache.catalina.connector.RequestFacade(实现HttpServletRequest)

Request-获取请求消息

  1. 获取请求消息数据

    1. 获取请求行数据
      • 方法:
        1. 获取请求方式:String getMethod()
        2. 获取虚拟目录:String getContextPath()
        3. 获取Servlet路径:String getServletPath()
        4. 获取get方式请求参数:String getQueryString()
        5. 获取请求URI:String getRequestURI() :/xxx/aaa
          • StringBuffer getRequestURL():http://localhost/xxx/aaa
        6. 获取协议及版本:String getProtocol()
        7. 获取客户机的IP地址:String getRemoteAddr()
    2. 获取请求头数据
      • 方法:
        1. 通过请求头名称获取请求头的值:String getHeader(String name)
        2. 获取所有的请求头名称:Enumeration< String > getHeaderName()
    3. 获取请求体数据
      • 请求体:只有POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
      • 步骤:
        1. 获取流数据
          • 获取字符输入流,只能操作字符数据:BufferedReader getReader()
          • 获取字节输入流,可以操作所有类型数据:ServletInputStream getInputStream()
        2. 再从流对象中获取数据
  2. 其它功能

    1. 获取请求参数(通用方式):get、post都可用

      1. 根据参数名称获取参数值:String getParameter(String name)
      2. 根据参数名称获取参数值的数组:String[] getParameterValues(String name)
      3. 获取所有请求的参数名称:Enumeration< String > getParameterNames()
      4. 获取所有参数的map集合:Map< String,String[] > getParameterMap()

      中文乱码问题:

      • get方式:tomcat 8 已经将get方式乱码问题解决了

      • post方式:会乱码

        解决:req.setCharacterEncoding("utf-8");

    2. 请求转发:一种在服务器内部的资源跳转方式

      • 步骤
        1. 通过req对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
        2. 使用RequestDispatcher对象来进行转发:forward(ServletRequest request,ServletResponse response)
      • 特点:
        1. 浏览器地址栏路径不发生变化
        2. 只能转发到当前服务器内部资源中
        3. 转发是一次请求
    3. 共享数据

      • 域对象:一个有作用范围的对象,可以在范围内共享数据

      • request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据

      • 方法:

        1. 存储数据:setAttribute(String name,Object obj)
        2. 通过键获取值:Object getAttribute(String name)
        3. 通过键移除键值对:removeAttribute(String name)
    4. 获取ServletContext

      • ServletContext getServletContext()

响应

  1. 响应行
    • 组成:协议/版本 响应状态码 状态码描述HTTP/1.1 200 OK
    • 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
      • 1xx:服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx状态码
      • 2xx:成功
      • 3xx:重定向-302(重定向),304(访问缓存)
      • 4xx:客户端错误-404(路径没有对应资源),405(请求方式没有对应的方法)
      • 5xx:服务器端错误-500(服务器内部出现异常)
  2. 响应头
    • 格式:头名称:值
    • 常见的响应头:
      1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
      2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据
        • 值:
          • in-line:默认值,在当前页面内打开
          • attachment;filename=xxx:以附件形式打开响应体,文件下载
  3. 响应空行
  4. 响应体:传输的数据

Response

功能:设置响应消息

  1. 设置响应行
    • 格式:HTTP/1.1 200 ok
    • 设置状态码:setStatus(int sc)
  2. 设置响应头:setHeader(String name,String value)
  3. 设置响应体
    • 使用步骤:
      1. 获取输出流
        • 字符输出流:PrintWriter getWriter()
        • 字节输出流:ServletOutputStream getOutputStream()
      2. 使用输出流,将数据输出到客户端浏览器

案例

完成重定向

  • 资源跳转的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 重定向到other
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// // 设置状态码302
// resp.setStatus(302);
// // 设置响应头location
// resp.setHeader("location","/other");

// 简单的重定向方法
resp.sendRedirect("/other");
}
  • 重定向的特点
    1. 地址栏发生变化
    2. 重定向可以访问其它站点(服务器)资源
    3. 重定向是两次请求
  • 路径写法
    1. 路径分类
      • 相对路径:通过相对路径不可以确定唯一资源(./xxx/aaa,以.开头的路径)
      • 绝对路径:通过绝对路径可确定唯一资源(/xxx/aaa,以/开头的路径)
        • 规则:判断定义的路径是给谁用的?(请求从哪里发出)如果是给客户端浏览器使用,需要加虚拟目录(项目的访问路径),如果是给服务器使用则不需要加虚拟目录
    2. 动态获取虚拟目录:request.getContextPath()

服务器输出字符数据到浏览器

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解码乱码问题
// 获取流对象之前设置编码
// resp.setCharacterEncoding("utf-8");
// resp.setHeader("content-type","text/html;charset=utf-8");
// 告诉浏览器发送的消息体数据的编码,建议浏览器使用该编码解码
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.write("hello你好");
}

服务器输出字节数据到浏览器

1
2
3
4
5
6
7
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取字节输出流
ServletOutputStream sos = resp.getOutputStream();
// 输出数据
sos.write("hello".getBytes());
}

验证码

  • 本质上是一张图片
  • 目的:防止恶意表单

ServletContext对象

  • 概念:代表整个Web应用,可以和程序的容器(服务器)通信

  • 获取:

    1. 通过request对象获取request.getServletContext();
    2. 通过HttpServlet获取this.getServletContext();
  • 功能:

    1. 获取MIME类型

      • MIME类型:在互联网通信过程中定义的一种文件数据类型
        • 格式: 大类型/小类型 text/html, image/jpeg
      • 获取:String getMimeType(String file)
    2. 域对象:共享数据

      • setAttribute(String name,Object value)
      • getAttribute(String name)
      • removeAttribute(string name)

      ServletContext对象范围:所有用户所有请求的数据

    3. 获取文件的真实(服务器)路径

      • 方法:String getRealPath(String path)
      1
      2
      3
      4
      5
      6
      7
      8
      // web目录下资源访问
      ServletContext context = this.getServletContext();
      String realPath = context.getRealPath("/b.txt");
      // WEB-INF目录下资源访问
      String realPath1 = context.getRealPath("/WEB-INF/c.txt");
      // src目录下资源访问
      String realPath2 = context.getRealPath("/WEB-INF/classes/a.txt");

案例

文件下载

  • 步骤

    1. 定义页面,编辑超链接href属性,指向Servlet,传递资源名称filename
    2. 定义Servlet
      1. 获取文件名称
      2. 使用字节输入流加载文件进内存
      3. 指定response的响应头:content-disposition:attachment;filename=xxx
      4. 将数据写到response输出流
    1
    <a href="/path/downloadServlet?filename=1.jpg">下载</a>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    @WebServlet("/downloadServlet")
    public class DownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String filename = req.getParameter("filename");

    ServletContext context = this.getServletContext();
    String realPath = context.getRealPath("/img/"+filename);
    FileInputStream fis = new FileInputStream(realPath);

    String mimeType = context.getMimeType(filename);
    resp.setHeader("content-type",mimeType);

    String agent = req.getHeader("user-agent");
    filename = DownloadUtil.getFileName(agent, filename);
    System.out.println(agent);
    System.out.println(filename);
    resp.setHeader("content-disposition","attachment;filename="+filename);

    ServletOutputStream sos = resp.getOutputStream();
    byte[] buff = new byte[1024*8];
    int len = 0;
    while((len=fis.read(buff))!=-1){
    sos.write(buff,0,len);
    }
    fis.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    this.doGet(req,resp);
    }
    }
  • 中文文件名问题

    • 解决思路:
      • 获取客户端使用的浏览器使用版本信息
      • 根据不同的版本信息,设置filename的编码方式不同
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class DownloadUtil {
    public static String getFileName(String agent,String filename) throws UnsupportedEncodingException {
    if(agent.contains("MSIE")){
    filename = URLEncoder.encode(filename,"utf-8");
    filename = filename.replace("+"," ");
    }else if(agent.contains("Firefox")){
    BASE64Encoder base64Encoder = new BASE64Encoder();
    filename = "=?utf-8?B?"+base64Encoder.encode(filename.getBytes("utf-8"))+"?=";
    }else{
    filename = URLEncoder.encode(filename,"utf-8");
    }
    return filename;
    }
    }