网络协议(十四)-应用层(HTTP)

HTTP
  • HTTP(Hyper Text Transfer Protocol), 译为超文本传输协议
    -- 是互联网中应用最广泛的应用层协议之一
    -- 设计HTTP最初的目的是: 提供一种发布和接收HTML页面的方法, 由URI来标识具体的资源
    -- 后面用HTTP来传递的数据格式不仅仅是HTML, 应用非常广泛

  • HTML(Hyper Text Markup Language): 超文本标记语言
    -- 用以编写网页

版本
  • 1991年, HTTP/0.9
    -- 只支持GET请求方法获取文本数据(比如HTML文档), 且不支持请求头, 响应头等, 无法向服务器传递太多信息

  • 1996年, HTTP/1.0
    -- 支持POST, HEAD等请求方法, 支持请求头, 响应头等, 支持更多种数据类型 (不再局限于文本数据)
    -- 浏览器的每次请求都需要与服务器建立一个TCP连接, 请求处理完成后立即断开TCP连接

  • 1997年, HTTP/1.1(最经典, 使用最广泛的版本)
    -- 支持PUT, DELETE等请求办法
    -- 采用持久连接(Connection: keep-alive), 多个请求可以共用一个TCP连接

  • 2015年, HTTP/2.0

  • 2018年, HTTP/3.0

报文格式
image.png
image.png
  • ABNF (Augmented BNF)
    -- 是BNF (Backus-Naur Form, 译为: 巴科斯-瑙尔范式)的修改, 增强版
    -- 在RFC 52234中表明: ABNF用作internet中通信协议的定义语言
    -- ABNF是最严谨的HTTP报文格式描述形式, 脱离ABNF谈论HTTP报文格式, 往往都是片面, 不严谨的

  • 关于HTTP报文格式的定义
    -- RFC 2616 4.HTTP Message(旧)
    -- RFC 7230 3.Message Format(新)

image.png
ABNF-核心规则
image.png
报文格式-request-line, status-line

request-line = method SP request-target SP HTTP-version CRLF
HTTP-version = HTTP-name "/" DIGIT"."DIGIT"
HTTP-name = %48.54.54.50;HTTP

GET /hello/ HTTP/1.1

status-line = HTTP-version SP status-code SP reason-phrase CRLF
status-code = 3DIGIT
reason-phrase = *(HTAB / SP / VCHAR / obs-text)

HTTP/1.1 200
HTTP/1.1 200 OK

报文格式 - header-filed, message-body

header-filed = filed-name ":" OWS field-value OWS
field-name = token
field-value = *(field-content / obs-fold)
OWS = *(SP / HTAB)

message-body = *OCTET

URL的编码
  • URL中一旦出现了一些特殊字符(比如中文, 空格), 需要进行编码
    -- 在浏览器地址栏输入URL时, 是采用UTF-8进行编码

  • 比如
    -- 编码前: https://www.baidu.com/s?wd=百度
    -- 编码前: https://www.baidu.com/s?wd=%E5%8D%8E%E4%B8%BA

请求方法
  • GET 常用于读取的操作, 请求参数直接拼接在URL的后面(浏览器对URL是有长度限制的)

  • POST 常用于添加, 修改, 删除的操作, 请求参数可以放到请求体中(没有大小限制)**(URL也可以拼接参数, 请求体里也拼接参数)**

  • HEAD 请求得到的与GET请求相同的响应, 但没有响应体
    -- 使用场景举例: 在下载一个大文件前, 先获取其大小, 再决定是否要下载. 以此可以节约带宽资源

  • OPTIONS 用于获取目的资源所支持的通信选项, 比如服务器支持的请求方法
    -- OPTIONS * HTTP/1.1

  • PUT 用于对已存在的资源进行整体覆盖

  • PATCH 用于对资源进行部分修改(资源不存在, 会创建新的资源)

  • DELETE 用于删除指定的资源

  • TRACE 请求服务器回显其收到的请求信息, 主要用于HTTP请求的测试和诊断

  • CONNECT 可以开启一个客户端与所请求资源之间的双向沟通的通道, 它可以用来创建隧道(tunnel)
    -- 可以用来访问采用了SSL(HTTPS)协议的站点

头部字段(Header Field)
  • 头部字段可以分为4种类型
    -- 请求头字段(Request Header Fields)
    ✅有关要获取的资源或客户端本身信息的消息头

-- 响应头字段(ResponseHeader Fields)
✅有关响应的补充信息, 比如服务器本身(名称和版本等)的消息头

-- 实体头字段(Entity Header Fields)
✅有关实体主体的更多信息, 比如主体长度(Content-Length)MIME类型

-- 请求头字段(General Header Fields)
✅同时适用于请求和响应消息, 但与消息主体无关的消息头

请求头字段
image.png
image.png
image.png
响应头字段
image.png
image.png
image.png
状态码(Status Code)
  • RFC 2616 10.Status Code Definitions规范中定义
    -- 状态码指示HTTP请求是否已成功完成

  • 状态码可以分为5
    -- 信息响应: 100~199
    -- 成功响应: 200~299
    -- 重定向: 300~399
    -- 客户端错误: 400~499
    -- 服务器错误: 500~599

  • 100 Continue
    -- 请求的初始部分已经被服务器收到, 并且并没有被服务器拒绝. 客户端应该继续发送剩余的请求, 如果请求已经完成, 就忽略这个响应
    -- 允许客户端发送带请求体的请求前, 判断服务器是否愿意接手请求(服务器通过请求头判断)
    -- 在某些情况下, 如果服务器在不看请求体就拒绝请求时, 客户端就发送请求体是不恰当或者低效的

  • 200 OK 请求成功

  • 302 Found 请求的资源被暂时移动到了由Location头部指定的URL

  • 304 Not Modified 说明无需再次传输请求内容, 也就是说可以使用缓存内容

  • 400 Bad Request 由于语法无效, 服务器无法理解该需求

  • 401 Unauthorized 由于缺乏目标资源要求的身份验证凭证

  • 403 Forbidden 服务器端有能力处理该请求, 但是拒绝授权访问

  • 404 Not Found 服务器端无法找到所请求的资源

  • 405 Method Not Allowed 服务器禁止了使用当前HTTP方法的请求

  • 406 Not Acceptable 服务器端无法提供与Accept-Charset以及Accept-Language指定的值相匹配的响应

  • 408 Request Timeout 服务器想要将没有在使用的连接关闭
    -- 一些服务器会在空闲连接上发送此信息, 即便是在客户端没有发送任何请求的情况下

  • 500 Internal Server Error 所请求的服务器遇到意外的情况并阻止其执行请求

  • 501 Not Implemented 请求的方法不被服务器支持, 因此无法被处理(注意和405的区别)
    -- 服务器必须支持的方法(即不会返回这个状态码的方法)只有GETHEAD

  • 502 Bad Gateway 作为网关或代理角色的服务器, 从上游服务器(如tomcat)中接收到的响应是无效的

  • 503 Service Unavailable 服务器尚未处于可以接受请求的状态
    -- 通常造成这种情况的原因是由于服务器停机维护或者已超载

form提交-常用属性
  • action 请求的URI
  • method 请求方法(GET, POST)
  • enctype POST请求时, 请求体的编码方式
    -- application/x-www-form-urlencoded(默认值)
    ✅用&分隔参数, 用=分隔键和值, 字符用URL编码方式进行编码

-- multipart/form-data
✅文件上传时必须使用这种编码方式

form提交-multipart/form-data
  • 参考RFC 1521
  • 请求头
    -- Content-Type: multipart/form-data; boundary=xxx
    image.png
同源策略
  • 浏览器有个同源策略(Same-Origin Policy)
    -- 它规定了: 默认情况下, AJAX请求只能发送给同源的URL
    -- 同源是指3个相同: 协议, 域名(IP), 端口

    image.png

  • img, script, link, iframe, video, audio等标签不受同源策略的约束

跨域资源共享
  • 解决AJAX跨域请求的常用方法
    -- CORS(Cross-Origin Resource Sharing) 跨域资源共享

  • CORS的实现需要客户端和服务器同时支持
    -- 客户端
    ✅所有的浏览器都支持(IE至少是IE10 版本)

-- 服务器
✅需要返回相应的响应头(比如Access-Control-Allow-Origin)
✅告知浏览器这是一个允许跨域访问的请求

后端在返回数据前就应该先判断origin和允许访问的是否一致, 否则就算浏览器报错跨域问题, 前端一样可以拿到数据, 后端的数据就存在不安全性

会话跟踪
  • HTTP是一种"无状态"(stateless)的协议
    -- 每次客户端访问网页时, 客户端都会打开与Web服务器的单独连接
    -- 并且服务器不会自动保留之前客户端请求的任何记录
    -- 所以服务器无法识别多个请求是否来自同一个客户端(比如浏览器)

  • 在很多应用场景中, 都有以下需求
    -- 服务器能够识别出多个请求是够来自同一个客户端
    -- 在来自同一个客户端的多个请求之间共享数据

  • 以上需求可以使用会话跟踪技术来完成. 在Java中, 实现会话跟踪的常用方法是
    -- Cookie
    -- Session

Cookie & Session
  • Cookie是直接存储在浏览器本地的一小串数据
    -- 使用document.cookie访问Cookie
    -- 在修改Cookie时, 只会修改其中提到的Cookie
    -- name=value必须被编码(encodeURIComponent)
    -- 一个Cookie最大为4kb, 每个网站最多有20+个左右的Cookie(具体取决于浏览器)

  • WindowsChrome浏览器的Cookie存放位置
    -- C:\Users\用户名\AppData\Local\Google\Chrome\User Data\Default\Cookies
    -- 使用SQLite数据库进行存储

Cookie的有效期
  • 如果没有设置Cookie的过期时间, 则当浏览器关闭时, Cookie就失效了

  • expries
    -- 必须完全采用GMT时区的格式, 可以受用date.toUTCString来获取
    -- 例如: expires=Tue, 19 Jan 2038 03:14:07 GMT

  • max-age
    -- 过期时间距离当前时间的秒数
    -- 例如: max-age=60

  • Cookie(只归一个浏览器管)
    -- 在客户端(浏览器)存储一些数据, 存储到本地磁盘(硬盘)
    -- 服务器可以返回Cookie交给客户端去存储

  • Session(针对用户浏览器的, 会话跟踪)
    -- 在服务器存储一些数据, 存储到内存中

Cookie的作用域
  • domainpath标识定义了Cookie的作用域, 即Cookie应该发送给哪些URL

  • domain
    -- 标识指定了哪些主机可以接受Cookie
    -- 如果不指定, 默认为当前文档的主机(不包含子域名); 如果指定了domain, 则一般包含子域名
    -- 例如: 如果设置domain=520it.com, 则Cookie也包含在子域名中(如bbs.520it.com)

  • path
    -- 标识指定了主机下的哪些路径可以接受Cookie, 子路径也会被匹配
    -- 例如:设置path=/docs, 则以下地址都会匹配
    ✔️/docs
    ✔️/docs/one/
    ✔️/docs/one/img

服务器设置Cookie
  • Cookie通常是由Web服务器使用响应头Set-Cookie设置的

  • 关于max-age

  • -在JavaScript中, 如果设置为0或者负数, 会立即删除Cookie
    -- 在Java中: 如果设置为0, 是立即删除Cookie; 如果设置为负数, 按默认情况处理

getSession内部的原理
  • 检查客户端是否有发送一个叫做JSESSIONIDCookie
    -- 如果没有
    ✔️创建一个新的Session对象, 并且这个Session对象会有一个id
    ✔️这个Session对象会保留在服务器的内存中
    ✔️在响应的时候, 会添加一个Cookie(JSESSIONID=Session对象的id)给客户端

-- 如果有
✔️返回idJSESSIONIDSession对象

JSESSIONID
  • 默认情况下, 当用户关闭浏览器时, Cookie中存储的JSESSIONID就会被销毁

  • 可以通过以下代码延长JSESSIONID在客户端的寿命

Cookie cookie = new Cookie("JSESSIONID", request.getSession().getId());
cookie.setMaxAge(3600);
response.addCookie(cookie);
Session的有效期
  • Session的有效期默认是30分钟
  • 可以在web.xml中配置失效时间(单位是分钟)
<session-config>
    <session-timeout>30</session-timeout>
 </session-config>
总结
  • Cookie
    -- 数据存储在浏览器客户端
    -- 数据有大小和数量的限制
    -- 适合存储一些小型, 不敏感的数据
    -- 默认情况下, 关闭浏览器后就会销毁

  • Session
    -- 数据存储在服务器端
    -- 数据没有大小和数量的限制
    -- 可以存储大型, 敏感的数据(比如用户信息)
    -- 默认情况下, 未使用30分钟后就会销毁

推荐阅读更多精彩内容