前言:跨域對於大多數開發人員並不陌生,可是當咱們遇到跨域的時候,大部分前端開發者都會說出一種解決方案:讓服務端設置一下參數就好了。那爲何服務端設置了這些參數就能解決跨域問題呢?除了服務端解決,還有沒有其餘的解決方案呢?本文會具體分析一下產生跨域的緣由以及其餘的解決跨域的方案。javascript
一、什麼是跨域
假若有一個頁面A(url:https://www.a.com
),頁面中有一個接口請求:https://www.b.com/getData
;當咱們在瀏覽器中發送這個請求的時候,瀏覽器就會報錯,錯誤信息大概以下:前端
Access to XMLHttpRequest at '
https://www.b.com/
' from origin 'https://www.a.com
' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.java
看到這個錯誤你們就知道了產生了跨域的問題。
二、跨域的緣由
知道了什麼是跨域,那爲何會產生跨域的問題呢?
瀏覽器爲了保護用戶的信息安全提出了同源策略(注:這裏須要特別注意一下是在瀏覽器中才會有同源策略的限制):node
- 協議相同
- 域名相同
- 端口相同
只有同時知足以上三個條件,咱們就說兩個url是同源的;因此,非同源之間就會產生跨域的問題。那既然知道了跨域產生的緣由,接下來咱們看一下幾種經常使用的解決跨域的方案。固然,也有其餘的方案,這裏就很少說了,你們能夠自行查詢一下。web
一、JSONP
jsonp全稱是json with padding,這是一種比較"古老"的解決跨域的方案,在那個年代,對於一些簡單的get請求,咱們能夠經過這種方式解決;可是其餘的一些複雜的請求(好比post),就須要用一些現代的方法解決了,那爲何jsonp不能發post請求呢?這要看一下jsonp解決跨域的原理:json
雖然瀏覽器有同源策略的限制,可是script標籤卻不受同源策略的限制,也就是經過script咱們能夠向不一樣的源發出請求。跨域
因爲script經過src發出的是get請求,因此jsonp的方式不不能解決post請求的跨域的。瀏覽器
// 客戶端代碼
function doJSONPRequestClickHandler() {
let script = document.createElement('script');
script.src = 'http://www.b.com/jsonp?callback=handleCallback';
document.body.appendChild(script);
}
// 回調
let handleCallback = function(res) {
console.log(res);
}
複製代碼
jsonp最關鍵的點就是http://www.b.com/jsonp?callback=handleCallback
後面的callback參數,服務端接收到請求以後要處理這個參數:安全
// 服務端用nodejs
app.get('/jsonp', (req, res) => {
let cb = req.query.callback;
res.send(cb + '("jsonp跨域成功")');
});
複製代碼
當瀏覽器接收到服務端的響應也就是成功加載了js,就會當即執行handleCallback('jsonp跨域成功');
以上就是jsonp跨域的原理。
二、代理
使用代理的方式解決跨域的原理也很好理解:同源策略只是在瀏覽器中限制的,離開了瀏覽器環境是不受同源策略的限制的,因此經過代理的方式,將咱們的接口請求先發到同源的代理,而後再經過代理服務器轉發到目的服務器。
下面是經過nodejs中間件代理的方式解決跨域:服務器
const http = require('http');
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer();
http.createServer((request, response) => {
proxy.web(request, response, {
target: 'https://www.b.com',
changeOrigin: true,
});
proxy.on('error', err => {
console.log(err);
});
}).listen(8081);
複製代碼
三、CORS
文章剛開始講到的「讓服務端設置一下參數」就是經過CORS的方式解決跨域的,那麼什麼是CORS呢?
CORS就是跨源資源共享,雖然瀏覽器有同源策略的限制,可是瀏覽器給咱們開了一個「後門」,瀏覽器是容許發送跨域請求的,可是須要服務端配合在響應頭中設置一些特定的response header:
- Access-Control-Allow-Origin: | *
- Access-Control-Allow-Methods: [, ]*
- Access-Control-Allow-Headers: [, ]*
- Access-Control-Allow-Credentials: true
這個值是告訴客戶端容許的源是哪些,能夠設置爲特定的一個源或者*,當設置爲的時候容許全部的源跨域請求,這個設置爲的時候要很是當心;
它告訴客戶端容許跨域請求的方法是什麼,好比GET,POST,PUT等,能夠設置多個
若是請求頭中有一些自定義的請求頭,就須要設置這個屬性了,能夠設置多個
當咱們的請求中須要帶一些cookie信息的時候,須要設置它的值爲true,須要注意一點,若是要使用這個屬性,那麼 Access-Control-Allow-Origin的值不能設置爲*。
CORS的設置以下:
app.post('/saveData', (req,res) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'POST');
res.header('Access-Control-Allow-Headers', 'custom');
console.log(req.body.name);
res.send('接到了數據' + req.body.name);
});
複製代碼
以上介紹了什麼是跨域,以及產生跨域的緣由;產生跨域時的幾種解決方案:jsonp、代理、cors...;經過以上的介紹,以後咱們再遇到跨域的問題的時候再也不只會說「讓服務端設置一下參數就好了」,可以明白爲何要服務端設置。 對於其餘的一些解決跨域的方案,本文中沒有說起,你們感興趣能夠本身研究一下,好比經過websocket、iframe等方式。