预检请求表现形式:
本机调试时,常常会出现同一个url请求两次的现象,如下图所示:
此时 web服务器IP地址是: 127.0.0.1:4200,请求的地址为 128.31.52.31:20000,形成了跨域。
便有了 preflight request(预检请求)。
为什么会有预检请求?
跨域资源共享标准新增了一组HTTP首部字段,允许服务器声明 A源站 通过浏览器有权限访问 B资源。
规范要求,对那些可能对服务器资源产生副作用的HTTP请求方式,浏览器必须使用OPTTIONS 发起一个预检请求,
从而获知服务器端是否允许该跨域请求。 服务器确认允许后,才发起实际的HTTP请求。
说白了,就是要先发起一个验证,看是否符合要求。与HTTP三次握手,有一点点类似。
触发预检请求条件
并非所有的跨域请求都会触发preflight request。
满足如下所有条件,即使跨域,也不会触发预检请求,一般称为简单请求。
/*
1、使用 GET、HEAD、POST 方法
2、Content-Type 只能是 text/plain、 multipart/form-data、 application/x-www-form-urlencoded
3、不添加自定义头部信息
*/
请查看如下demo.
<!DOCTYPE html> <html> <head></head> <body> <script type="text/javascript"> fetch('http://localhost:8887',{ method:'POST' }) </script> </body> </html>
const http=require('http'); http.createServer((request,response)=>{ response.writeHead(200,{ 'Access-Control-Allow-Origin':'*' }); response.end('123'); }).listen(8887);
分别启动成不同的端口路径,则模拟成跨域请求。此时是不会有 OPTIONS 请求。
那么,怎么才能触发 预检请求呢?
其实,与简单请求的条件相反。
当请求满足下述任一条件时,即应首先发送预检请求:
1、使用如下 任一 Http请求方式
PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
2、设置了对 CORS安全的首部字段集合 之外的首部字段,集合如下:
Accept、Accept-Language、Content-Language、Content-Type、DPR、Viewport-Width、Width、Downlink、Save-Data
3、Content-Type的值不属于下列之一:
text/plain、Application/x-www-form-urlencorded、multipart/form-data
如下Demo可以模拟请求出现 OPTIONS请求。
HTML:
<!DOCTYPE html> <html> <head></head> <body> <script type="text/javascript"> fetch('http://localhost:8887',{ method:'POST', headers: { 'X-Test-CORS':'shelf-cors' } }) </script> </body> </html>
JS
const http=require('http'); http.createServer((request,response)=>{ response.writeHead(200,{ 'Access-Control-Allow-Origin':'*', 'Access-Control-Allow-Headers':'X-Test-CORS'
}); response.end('123'); }).listen(8887);
在请求头部添加自定义头部,便形成preflight request.
预请求 Request Header 中的 Access-Control-Request-Method 指定了真正的请求方式。