Request
请求行
GET / HTTP/1.1 // Method、URL、HttpVerson
其中,Method
包括 GET POST HEAD PATCH PUT DELETE TRACE CONNECT OPTIONS
-
CONNECT
保留将来使用 -
OPTIONS
- 请求查询服务器的性能,或者查询与请求资源相关的功能选项
- 预检请求
消息报头
-
Accept
指定客户端接受哪些类型的信息(MIME
),如image/gif(GIF图片)
,text/html(HTML文本)
-
Accept-Charset
客户端接受的字符集,如gb2312,utf-8
-
Accept-Encoding
客户端接受的内容编码,如gzip,deflate(压缩类型),identity(默认行为)
-
Accept-Language
客户端接受的自然语言,如zh-cn,zh;q=0.5,zh-cn,zh
分别表示简体中文和中文,其中优先支持简体中文,q
表示权重系数,范围[0,1]
,默认值为1
;值越大,请求越倾向于;
前的类型所表示的内容;如果设置为0
,则用于提醒服务器哪些是客户端不支持的内容类型。*
是通配符,表示任意语言。 -
Authorization
证明客户端有权查看某个资源; -
Host
指定被请求资源的主机和端口号; -
User-Agent
用户代理:操作系统及版本、CPU类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件; -
Content-Type
Body的编码方式。
请求正文
Response
状态行
HTTP/1.1 200 OK // 协议及版本、状态码、状态描述
状态码可分为 5
大类:
-
1XX
指示信息 -
2XX
成功 -
3XX
重定向 -
4XX
客户端错误 -
5XX
服务端错误
消息报头
- 响应报头
-
Location
重定向接受者到一个新的位置 -
WWW-Authontication
包含在401
(未授权)的响应消息中 -
Server
包含了服务器用来处理请求的软件信息,如Apache-Coyote/1.1
-
- 实体报头
-
Content-Encoding
实体正文的编码 -
Content-Language
资源所用的自然语言。如果没有设置该域,则认为实体内容支持所有语言; -
Content-Length
正文长度,以字节形式存储的十进制数字来表示 -
Content-Type
实体正文的媒体类型 -
Expires
响应过期的日期和时间
-
响应正文
跨域
同源策略: 协议protocol
、主机host
、端口号port
一致
跨域 是浏览器的同源策略所致,与后端无关。HTTP
请求正常发送了,后端也正常处理了,只是请求结果被浏览器拦截了。
跨域接口的特征:Network -> General
Referrer Policy: no-referrer-when-downgrade
后端允许跨域的响应头:
// 允许 http://localhost:3000 跨域
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
设置为 *
则表示所有域名都可以跨域访问。
简单请求与复杂请求
查看 Network
可知,有的请求会发送两次,第一次请求的方法是OPTIONS
,也就是预检请求。
为什么会发送预检请求?
我们都知道浏览器的同源策略,出于安全考虑,浏览器会限制从脚本发起的跨域
HTTP
请求,像AJAX、Fetch
都遵循同源策略;
浏览器限制跨域请求一般有两种方式:1> 限制发起跨域请求;2> 跨域请求可以正常发起,但浏览器会拦截返回的结果。
一般浏览器都是第二种方式限制跨域请求,也就是说请求已到达服务器,且有可能操作了数据库,但返回的结果被浏览器拦截了,那么我们就获取不到返回结果。虽然这是一次失败的请求,但可能对数据库里的数据产生了影响。
为了防止这种情况的发生,对这种可能对服务器数据产生副作用的HTTP
请求方法,浏览器必须先使用OPTIONS
方法发起一个预检请求,从而获知服务器是否允许该跨域请求。如果允许,则发送带数据的真实请求;如果不允许,则阻止发送带数据的真实请求。
由此,HTTP
请求分为 简单请求 和 预检请求
- 简单请求不会触发
CORS
预检请求GET、HEAD、POST
- 对于
POST
请求,Content-Typ
e 的值必须符合application/x-www-form-urlencoded、multipart/form-data、text/plain
,否则视为预检请求。
- 预检请求要求 必须首先使用
OPTIONS
方法发送一个请求到服务器-
PATCH PUT DELETE TRACE CONNECT OPTIONS
这些请求默认就是预检请求; - 请求头中设置了自定义的字段,即使当前请求属于简单请求,也会被视为预检请求;
axios.get('/api/users', { headers: { 'X-Token': 'xxxxxxxx' } })
-
Content-Type
的值不属于application/x-www-form-urlencoded、multipart/form-data、text/plain
中的任何一种。
-
因此,服务器在允许跨域时,还要额外处理预检请求OPTIONS
,允许预检请求跨域!
res.writeHead(200, {
'Access-Control-Allow-Origin': 'http://localhost:3000',
'Access-Control-Allow-Headers': 'X-Token,Content-Type',
'Access-Control-Allow-Methods': 'PUT'
})
跨域中的Cookie
通常在跨域的情况下,Cookie
是无效的,这也是 Session
无效的原因。
- 服务器让客户端设置
Cookie
的响应头:res.setHeader('Set-Cookie', 'cookie1=va3333')
- 服务端获取
Cookie:req.headers.cookie
-
axios
发请求默认是不带Cookie
的,需要设置:axios.defaults.withCredentials = true
- 另外,在服务端的请求中设置允许
Cookie
,预检请求和真实请求都要加res.setHeader('Access-Control-Allow-Credentials', 'true')
这样在跨域的情况下也能获取到Cookie
!
express
设置反向代理,可以解决跨域问题
const express = require('express')
const proxy = require('http-proxy-middleware')
const app = express()
app.use('/api', proxy({
target: 'http://localhost:4000',
changeOrigin: false
}))
正向代理与反向代理
-
正向代理 在客户端,客户端配置代理服务器 去请求目标服务器;如
Webpack
的代理,VPN
-
反向代理 在服务端,代理服务器就是客户端请求的目标服务器,但在服务端,这个代理服务器会转发请求到其他机器;
Nginx
和Node
常被用做代理请求的服务。
监控
埋点 - 上报信息的方式
AXIOS
img.src
const img = new Image()
img.src='/api/report?xxx=yyy'
//....还有很多
网友评论