根據前端跨域的那些事這篇文章中的跨域的理解這一塊,我們重新創建兩個服務,第一個服務使用了test.html
const http = require('http') const fs = require('fs') http.createServer(function (request, response) { console.log('request come', request.url) const html = fs.readFileSync('test.html', 'utf8') response.writeHead(200, { 'Content-Type': 'text/html' }) response.end(html) }).listen(8888) console.log('server listening on 8888')
test.html中使用fetch來發送請求,並且設置了一個自定義的請求頭'X-Test-Cors': '123'
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> 測試 </body> <script> fetch('http://localhost:8887', { method: 'POST', headers: { 'X-Test-Cors': '123' } }) </script> </html>
第二個服務,還是設置了'Access-Control-Allow-Origin': '*'允許所有域名下的請求
const http = require('http') http.createServer(function (request, response) { console.log('request come', request.url) response.writeHead(200, { 'Access-Control-Allow-Origin': '*' }) response.end('123') }).listen(8887) console.log('server listening on 8887')
啟動兩個服務,請求訪問第一個服務中的test.html,test.html發送了一個請求
運行結果看到,報錯了,在跨域請求中加了自定義的請求頭是不允許的(JSONP請求沒法設置自定義請求頭),其實請求是發送成功了的,並且也有數據返回只是瀏覽器因為安全策略將返回的數據攔截掉了
這時候就要用到CORS的預請求,在CORS中有一些限制,如下
在跨域的情況下,允許的請求方法只有:GET,HEAD, POST,這三個方法不需要預請求驗證,其它的請求方法默認都是不允許的,瀏覽器要有一個預請求的方式去驗證,驗證通過之后才能發送請求
在跨域的情況下,允許的Content-Type:test/plain,multipart/form-data,application/x-www-form-urlencoded,除了這三種之外的其它Content-Type同樣需要預請求去驗證,驗證通過之后才能發送請求
在跨域的情況下,自定義請求頭也會被限制,需要預請求去驗證,驗證通過之后才能發送請求
如果我們要允許自定義的請求頭在請求里發送,那么我們需要返回一個新的請求頭來告訴瀏覽器我們這個自定義的請求頭是允許的,在第二個服務中設置返回的新的請求頭
const http = require('http') http.createServer(function (request, response) { console.log('request come', request.url) response.writeHead(200, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'X-Test-Cors' }) response.end('123') }).listen(8887) console.log('server listening on 8887')
運行結果顯示,比之前多一個請求,第一個其實就是瀏覽器驗證的一個請求,第二個才是實際發送的請求
同樣請求方法和Content-Type也是可以設置的,沒設置之前我們使用PUT的請求方式來請求是會報錯的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> 測試 </body> <script> fetch('http://localhost:8887', { method: 'PUT', headers: { 'X-Test-Cors': '123' } }) </script> </html>
const http = require('http') http.createServer(function (request, response) { console.log('request come', request.url) response.writeHead(200, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'X-Test-Cors', 'Access-Control-Allow-Methods': 'POST, PUT, DELETE', }) response.end('123') }).listen(8887) console.log('server listening on 8887')
設置之后,就可以使用PUT方式去請求了,運行結果可以看到第二個實際的請求PUT成功的
還有一個設置就是:Access-Control-Max-Age:1000,表示運行這種跨域的請求在第一個預請求驗證通過后,1000秒之內第二次請求的時候不需要發送預請求了,可以直接發送實際的請求(也就是上面說的第二個實際的請求)
const http = require('http') http.createServer(function (request, response) { console.log('request come', request.url) response.writeHead(200, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'X-Test-Cors', 'Access-Control-Allow-Methods': 'POST, PUT, DELETE', 'Access-Control-Max-Age': '1000' }) response.end('123') }).listen(8887) console.log('server listening on 8887')
運行結果可以看到,當我第一個發送請求的時候是需要預請求驗證的,當我刷新頁面再次請求的時候,就已經不需要預請求驗證了