消息队列篇--通信协议篇--HTTP(请求体格式,响应体格式,Request和Response对象,ServletContext,Cookie和Session技术等)

HTTP(超文本传输协议:Hyper Text Transfer Protocol)是一种应用层协议,主要用于在Web浏览器和服务器之间传输超文本(如HTML页面),也可以用于服务端与服务端之间的通信。它是一个无状态的请求-响应协议,客户端发送请求,服务器返回响应。

特点:

  • 简单易用,广泛支持。
  • 支持多种方法(GET、POST、PUT、DELETE等)。
  • 支持RESTful API设计。
  • 可以通过HTTPS提供安全传输。
  • 基于TCP/IP的高级协议
  • 默认端口号:80
  • 基于请求/响应模型的:一次请求对应一次响应
  • 无状态的:每次请求之间相互独立,不能交互数据。适合短连接的交互。
    在1.0版本:每一次请求响应都会建立新的连接
    在1.1版本:支持连接复用(当前主流)

适用场景:

  • Web应用程序和API服务。
  • 适用于短连接、无状态的请求-响应模式。
  • 适用于需要简单、快速开发的应用。

1、请求消息格式

(1)、客户端发送给服务器端的数据

组成:
请求行,请求头,请求空行,请求体四个部分。

1、请求行(固定格式:请求方式 请求URI,请求协议/版本)

示例:

GET  /login.html  HTTP/1.1
2、请求头(告诉服务器一些信息,键值对形式)

常见的请求头:

  • User-Agent:浏览器告诉服务器,使用的浏览器版本信息
    • 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
  • Referer:http://localhost/login.html
    • 告诉服务器,我(当前请求)从哪里来?主要作用有两个:防盗链和统计工作。
3、请求空行(一个空行)

用于分割POST请求的请求头,和请求体的

4、请求体(正文)

封装POST请求消息的请求参数的。(get方式会追加到url尾部)

5、完整HTTP请求消息示例
post请求示例:
POST /login.html HTTP/1.1                  // 请求行
Host: localhost                            // 请求头
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
                     			             // 请求空行
username=zhangsan	                      // 请求体

解释:

  • 请求行指定了这是一个POST请求,请求的URI地址为/login.html,使用的是HTTP 1.1协议版本。
  • Host: 指定请求的目标主机名和端口号(如果没有指定端口号,默认为 80)。
  • User-Agent: 提供了客户端是浏览器的信息。这里的信息表明请求是由 Firefox 浏览器发起的,操作系统是 Windows 7(Windows NT 6.1),并且浏览器版本是 60.0。
  • Accept: 客户端可以接受的内容类型。在这个例子中,客户端优先接受 text/html、application/xhtml+xml 和 application/xml 类型的内容。q 参数表示质量值(quality value),范围从 0 到 1,值越大表示优先级越高。/;q=0.8 表示客户端也可以接受其他任何类型的内容,但优先级较低。
  • Accept-Language: 客户端可以接受的语言。这里指定了几种语言及其优先级:简体中文(zh-CN)、繁体中文(zh-TW 和 zh-HK)以及英语(en-US 和 en),其中 zh-CN 的优先级最高。
  • Accept-Encoding: 客户端可以接受的内容编码方式。这里表示客户端支持 gzip 和 deflate 压缩格式,这有助于减少传输的数据量。
  • Referer: 表示当前请求是从哪个页面发起的。在这个例子中,请求是从 http://localhost/login.html 发起的,通常用于跟踪用户的浏览历史。
  • Connection: 指定连接是否保持打开状态。keep-alive 表示客户端希望在请求完成后保持连接打开,以便后续请求可以重用这个连接,从而提高性能。
  • Upgrade-Insecure-Requests: 这个头部告诉服务器客户端希望升级不安全的请求(即通过 HTTP 发出的请求)到 HTTPS。值为 1 表示启用此功能。
  • 中间的空行为请求空行,必须存在。
  • 请求体(Body): 在 POST 请求中,数据通常放在请求体中。在这个例子中,请求体包含了一个简单的键值对 username=zhangsan,表示用户名字段的值是 zhangsan。实际应用中,登录表单可能还会包含密码等其他字段。
get请求示例:
GET /search?author=J.K.Rowling&category=fantasy&sort=price_asc&page=1 HTTP/1.1
Host: bookstore.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://bookstore.example.com/home
Connection: keep-alive
Upgrade-Insecure-Requests: 1

解释:
get请求和post请求参数整体上是差不多的,主要区别在于get请求的参数追加在URI后面,所以get请求没有请求体,因此也不需要请求空行了。

(2)、Request对象和使用

服务器端创建的,用来获取客户端发出的请求。

1、常用方法
//1. 获取请求方式 :GET
String method = request.getMethod();
System.out.println(method);
//2.(*)获取上下文:/day14
String contextPath = request.getContextPath();
System.out.println(contextPath);
//3. 获取Servleturl路径: /demo1
String servletPath = request.getServletPath();
System.out.println(servletPath);
//4. 获取get方式请求参数:name=zhangsan
String queryString = request.getQueryString();
System.out.println(queryString);
//5.(*)获取请求URI:/day14/demo1
String requestURI = request.getRequestURI();           // URI可控制所有IP的请求
StringBuffer requestURL = request.getRequestURL();    // URL可控制指定IP的请求
//6. 获取协议及版本:HTTP/1.1
String protocol = request.getProtocol();
System.out.println(protocol);
//7. 获取客户端的IP地址:
String remoteAddr = request.getRemoteAddr();
System.out.println(remoteAddr);

注意:
URL: 统一资源定位符。示例如:http://localhost/day14/demo1
URI: 统一资源标识符。示例如:/day14/demo1

2、获取请求头信息
//1.获取所有请求头名称
Enumeration<String> headerNames = request.getHeaderNames();
//2.遍历
while(headerNames.hasMoreElements()){
    String name = headerNames.nextElement();
    //根据名称获取请求头的值
    String value = request.getHeader(name);
    System.out.println(name+"---"+value);
}
3、防盗链示例
String referer = request.getHeader("referer");
System.out.println(referer); // 如:http://localhost/day14/login.html
if(referer != null ){
    if(referer.contains("/day14")){
        // 正常访问
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("播放电影....");
    }else{
        // 盗链,重定向
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("想看电影吗?来优酷吧...");
    }
}
4、获取请求参数信息
// 获取指定名称参数值(多个仅获取第一个)
 String username = request.getParameter("username");

// 获取指定名称参数数组(前端传多个时都可获取)
 String[] hobbies = request.getParameterValues("hobby");
 // 获取所有参数的map集合
 Map<String, String[]> parameterMap = request.getParameterMap();
 Set<String> keyset = parameterMap.keySet();   // keys
 for (String name : keyset) {
     //获取键获取值
     String[] values = parameterMap.get(name);     // values
     System.out.println(name);   
     for (String value : values) {
         System.out.println(value);
     }
     System.out.println("-----------------");
 }
5、请求转发
request.getRequestDispatcher("/requestDemo9").forward(request,response);

请求转发说明:

  • 浏览器地址栏路径不发生变化。
  • 只能转发到当前服务器内部资源中。跨域不能转发
  • 转发是一次请求。(可以使用request对象进行共享数据)

2、响应消息格式

(1)、服务器端发送给客户端的数据

组成:响应行,响应头,响应空行,响应体四个部分。

1、响应行(协议/版本 响应状态码 状态码描述)

示例:

HTTP/1.1  200  OK

解释:
状态码分类:
– 1xx:服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx多状态码
– 2xx:响应成功,返回200;部分成功返回206等。
– 3xx:重定向。代表:302(重定向),304(访问缓存)
– 4xx:客户端错误。404:请求路径没有对应的资源。405:请求方式没有对应的doXxx方法等。
– 5xx:服务器端错误。代表:500(服务器内部出现异常)

2、响应头(告诉浏览器一些信息,键值对形式)

常见的响应头:
Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
Content-disposition:服务器告诉客户端以什么格式打开响应体数据

  • in-line:默认值,在当前页面内打开
  • attachment;filename=xxx:以附件形式打开响应体。文件下载
3、 响应空行(一个空行)

用于分割响应头和响应体

4、响应体(正文)

传输的数据

5、完整响应示例:
HTTP/1.1 200 OK                               // 响应行
Content-Type: text/html;charset=UTF-8             // 响应头
Content-Length: 101
Date: Wed, 06 Jun 2018 07:08:42 GMT
                                            // 响应空行
<html>                                       // 响应数据
  <head>
    <title>$Title$</title>
  </head>
  <body>
  hello , response
  </body>
</html>

(2)、Response对象

服务器创建的对象,用来封装返回消息。

1、重定向示例
// 动态获取上下文
 String contextPath = request.getContextPath();
 // 简单的重定向
 response.sendRedirect(contextPath+"/responseDemo2");   // 重定向相同域名
 //response.sendRedirect("http://www.itcast.cn");      // 可以重定向到不同域

解释:(重定向和转发区别)
重定向的特点:(redirect)

  • 地址栏发生变化
  • 重定向可以访问其他站点(即:可跨服务访问)的资源
  • 重定向是两次请求。不能使用request对象来共享数据
    转发的特点:(forward)
  • 转发地址栏路径不变
  • 转发只能访问当前服务器下的资源
  • 转发是一次请求,可以使用request对象来共享数据
2、返回字符类型响应(如:返回字符串)
//获取流对象之前,设置流的默认编码:ISO-8859-1 设置为:GBK
response.setCharacterEncoding("utf-8");

//告诉浏览器,服务器发送的消息体数据的编码。建议浏览器使用该编码解码
response.setHeader("content-type","text/html;charset=utf-8");
// 设置content-type的简单的形式,实际相当于上一句的设置请求头
response.setContentType("text/html;charset=utf-8");

// 获取字符输出流
PrintWriter pw = response.getWriter();
// 设置字符串到响应体中
pw.write("你好啊啊啊 response");
//pw.write("<h1>hello response</h1>");
返回字节类型响应(如:返回图片)
int width = 100;      // 定义宽
int height = 50;     //  定义高
//1.创建一对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2.美化图片
//2.1 填充背景色
Graphics g = image.getGraphics();  // 定义画笔
g.setColor(Color.PINK); //设置画笔颜色
g.fillRect(0,0,width,height);    // 填充背景色(前两个为起点,后两个参数为终点)
//2.2画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width - 1,height - 1);   // 边框也占1个像素,所以最后要减去1

String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789";
//生成随机角标
Random ran = new Random();
for (int i = 1; i <= 4; i++) {
    int index = ran.nextInt(str.length());
    char ch = str.charAt(index);//随机字符
    //2.3写验证码
    g.drawString(ch+"",width/5*i,height/2);  // 字符值,和字符坐标
}
// 2.4画干扰线
g.setColor(Color.GREEN);
//随机生成坐标点
for (int i = 0; i < 10; i++) {
    int x1 = ran.nextInt(width);
    int x2 = ran.nextInt(width);
    int y1 = ran.nextInt(height);
    int y2 = ran.nextInt(height);
    g.drawLine(x1,y1,x2,y2);      // 绘制干扰线
}
//3.将图片输出到页面展示
ImageIO.write(image,"jpg",response.getOutputStream());

3、ServletContext对象

ServletContext代表整个web应用,可以和运行程序的容器(服务器)来通信。

(1)、获取方式

1、通过request对象获取
request.getServletContext();
2、通过HttpServlet获取
this.getServletContext();

解释:
两者皆可获取,获取为同一个对象。使用时选择其中一个就行。

(2)、主要功能

1、获取MIME类型

MIME类型:在互联网通信过程中定义的一种文件数据类型。
格式: 大类型/小类型 如: text/html image/jpeg
示例:

//1、通过HttpServlet获取
ServletContext context = this.getServletContext();
//2、定义文件名称
String filename = "a.jpg";
//3、获取MIME类型
String mimeType = context.getMimeType(filename);    // 返回:image/jpeg
2、域对象
(1)、共享数据

通过ServletContext可以设置和获取全局变量。不过通常不建议使用,要谨慎使用。

示例:

setAttribute(String name,Object value)   // 设置全局属性
getAttribute(String name)    // 获取全局属性
removeAttribute(String name)   // 移除全局属性
(2)、获取文件的真实(服务器)路径

ServletContext相对ClassLoader据有更全面的类型加载,后者仅限于src目录下的java文件。前者可以加载整个web服务下的所有文件。

示例:

 // 通过HttpServlet获取
 ServletContext context = this.getServletContext();
 // 获取文件的服务器路径
 String b = context.getRealPath("/b.txt"); //web目录下资源访问(与WEB-INF同级目录的文件)
 String c = context.getRealPath("/WEB-INF/c.txt"); //WEB-INF目录下的资源访问
 String a = context.getRealPath("/WEB-INF/classes/a.txt"); //src目录下的资源访问

(3)、综合示例

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 一、获取文件,生成文件字节流
    String filename = request.getParameter("filename");    // 入参文件名称
    ServletContext servletContext = this.getServletContext();   // 获取web对象
    String realPath = servletContext.getRealPath("/img/" + filename);   // web对象获取到文件的真实路径
    FileInputStream fis = new FileInputStream(realPath);  // 获取文件的字节流

    // 二、response设置,文件类型和输出方式
    String mimeType = servletContext.getMimeType(filename); // 获取文件的mime类型
    response.setHeader("content-type",mimeType);     // 设置输出文件的mime类型
    //解决中文文件名乱码问题
    //1. 获取user-agent请求头,包含浏览器版本信息,可以识别请求发起的浏览器信息
    String agent = request.getHeader("user-agent");
    //2. 针对不同浏览器处理名称,防止中文乱码
    filename = getFileName(agent,filename);
    response.setHeader("content-disposition","attachment;filename="+filename);   // 设置浏览器以文件方式打开响应值

    // 三、文件流写入response字节流中
    ServletOutputStream sos = response.getOutputStream();
    byte[] buff = new byte[1024 * 8];
    int len = 0;
    while((len = fis.read(buff)) != -1){
        sos.write(buff,0,len);
    }
    fis.close();
}

public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
    if (agent.contains("MSIE")) {
        // IE浏览器
        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;
}

4、会话技术–Cookie和Session

会话:
客户端和服务器之间的一次连接访问过程,包含多次请求和响应。

会话特点:
在一次会话的范围内的多次请求间,共享数据。

主要技术:

  • 客户端会话技术:Cookie
  • 服务器端会话技术:Session

(1)、Cookie技术

客户端会话技术,将数据保存到客户端。

1、原理

服务端在response中设置set- cookie,客户端在收到响应头包含set-cookie后,会自动添加该信息到会话的cookie中,之后会话中的每次的请求都会包含这个cookie的请求头信息。
在这里插入图片描述
代码示例:(服务端)

//1.创建Cookie对象
Cookie c = new Cookie("msg","hello");
//2.设置Cookie
response.addCookie(c);   // 会返回set-cookie的响应头给客户端,值为msg:hello
//3. 获取Cookie
Cookie[] cs = request.getCookies();
 //获取数据,遍历Cookies
 if(cs != null){
     for (Cookie c : cs) {
         String name = c.getName();
         String value = c.getValue();
         System.out.println(name+":"+value);
     }
 }
2、使用细节

一次性可以设置多个cookie值:

Cookie c1 = new Cookie("msg","hello");
Cookie c2 = new Cookie("name","zhangsan");
response.addCookie(c1);
response.addCookie(c2);

设置保存时间:
默认情况下,当浏览器关闭后,Cookie数据被销毁,也可以自定义设置cookie的有效时间。
自定义设置cookie有效时间可以使用setMaxAge(int seconds)方法。
参数示例:

  • 正数:将Cookie数据写到硬盘的文件中。持久化存储。并指定cookie存活时间,时间到后,cookie文件自动失效(注意:即使关闭浏览器再次打开,cookie也会在有效时间内存在)
  • 负数:默认值(关闭浏览器,cookie消失)
  • 0:删除cookie信息
//1.创建Cookie对象
Cookie c1 = new Cookie("msg","hahaha");
//2.设置cookie的存活时间
//c1.setMaxAge(30);// 将cookie持久化到硬盘,30秒后会自动删除cookie文件
//c1.setMaxAge(-1);   // 默认,可不设置。关闭浏览器cookie失效
c1.setMaxAge(0);// 删除Cookie,通知浏览器立刻删除cookie
//3.发送Cookie
response.addCookie(c1);

cookie中是否能使用中文?
Tomcat 8之前不能存储中文;tomcat8及之后可以存中文。
如果tomcat8之前存中文,或存一些特色的字符,如空格怎么办?
解决方法:通过URL编码处理

// URL编码
str_date = URLEncoder.encode(str_date,"utf-8");
// URL解码:
String value = cookie.getValue();
value = URLDecoder.decode(value,"utf-8");

cookie共享问题:
默认不能实现共享。但是可以通过一些配置实现共享。
如果服务部署在同一个tomcat中:
setPath(String path):设置cookie的获取范围。
如果要共享,则可以将path设置为"/“。
如果服务部署在不同的tomcat中:
setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享。
解释:
setDomain(”.baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享。

cookie大小和限制:
单个cookie 的大小有限制4kb(解释:1kb可以存1024个字节,即可以存1024个英文字符或512个中文字符)内,同一个域名最多不能超过20个。

(2)、session技术

服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。如:HttpSession。

示例:

//1.获取session
HttpSession session = request.getSession();
//2.存储数据
session.setAttribute("msg","hello session");
//3.获取数据
Object msg = session.getAttribute("msg");
System.out.println(msg);
1、原理

Session的实现是依赖Cookie的。
服务器使用session时,会判断是否存在cookie(cookie携带唯一的JSESSIONID才能确保服务器能正确找到会话的session),如果没有cookie或者cookie不包含JSESSIONID,服务端则会给浏览器添加set-cookie:JSESSIONID=xxx的返回响应头,同时生成session对象,标记id为xxx。 之后浏览器携带cookie:JSESSIONID=xxx的请求头再次访问,后台则可以正确拿到session对象。
在这里插入图片描述

2、使用细节

当客户端关闭后再次打开客户端,服务器不关闭,两次获取session是否为同一个吗?
默认情况下不是同一个session,因为关闭浏览器会清除cookie缓存。
如何设置为同一个的方案:
创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。

Cookie c = new Cookie("JSESSIONID",session.getId());
c.setMaxAge(60*60);
response.addCookie(c);

session什么时候被销毁?
(1)、服务器关闭
(2)、session对象调用invalidate() 。
(3)、session默认失效时间 30分钟。
示例:
选择性配置修改(tomcat的web.xml中配置,默认分钟)

<session-config>
    <session-timeout>30</session-timeout>
</session-config>

乘风破浪会有时,直挂云帆济沧海!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值