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
报文格式
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(新)
ABNF-核心规则
报文格式-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)
✅同时适用于请求和响应消息, 但与消息主体无关的消息头
请求头字段
响应头字段
状态码(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
的区别)
-- 服务器必须支持的方法(即不会返回这个状态码的方法)只有GET
和HEAD
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
(具体取决于浏览器)Windows
中Chrome
浏览器的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
的作用域
domain
和path
标识定义了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
内部的原理
- 检查客户端是否有发送一个叫做
JSESSIONID
的Cookie
-- 如果没有
✔️创建一个新的Session
对象, 并且这个Session
对象会有一个id
✔️这个Session
对象会保留在服务器的内存中
✔️在响应的时候, 会添加一个Cookie(JSESSIONID=Session对象的id)
给客户端
-- 如果有
✔️返回id
为JSESSIONID
的Session
对象
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
分钟后就会销毁