当浏览器发起跨域请求时,如果请求属于 “简单请求” 浏览器就直接发,如果属于 “复杂请求” ,浏览器会先自动发送一个 预检请求 (OPTIONS) 来询问服务器是否允许本次的跨域请求。
当发起跨域请求时,符合下面所有条件的请求,是简单请求:
GET / POST / HEADAcceptRange (只允许简单的范围,比如:byte=256- 或者 byte-127-255)Accept-LanguageContent-LanguageContent-Type 并且值仅限于以下三者之一:
application/x-www-form-urlencoded,multipart/form-data,text/plainX-token)application/json 类型的 POSTCredentials (携带 cookie)ReadableStream 对象简单请求示例:
fetch('https://api.example.com/data', {
method: 'GET',
})
fetch('https://api.example.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'username=admin&password=123'
})只要不满足简单请求的条件,就属于 “复杂请求“ , 浏览器会自动发一个 OPTIONS 请求,看服务端是否允许当前的跨域请求,如果服务端允许,再发送真正的请求。
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'abc' // 自定义头
},
body: JSON.stringify({ name: 'Jack' })
})OPTIONS 请求 (不带 body ),询问服务端是否支持这个自定义 headerAccess-Control-Allow-* 响应头,才会再发送 POST 请求。预检请求:
“需要预检的请求” 必须先使用 OPTIONS 方法发起一个预检请求到服务端,以获知服务器是否允许该实际请求。
“预检请求” 的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
预检请求的相应结果一般包含下面几个响应头:
Access-Control-Allow-Origin: https://foo.example
表明允许 https://foo.example 的域访问服务器的资源。
Access-Control-Allow-Methods: POST, GET, OPTIONS
表明服务端允许客户端使用 POST、GET、OPTIONS 三种方法发起请求。
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
表明服务端允许请求中携带 X-PINGOTHER, Content-Type 请求头(自定义请求头)。
Access-Control-Max-Age: 86400
表明服务端给定了该预检请求可供缓存的时间长短,单位为 s , 默认值是 5s,在有效时间内,浏览器无需为同一请求再次发起预检请求。
注:
如果不是跨域请求,即使请求是复杂请求,浏览器也 不会 发出预检请求。
附:
跨域报错:
