瀏覽器做爲請求方與被請求方的域名、協議、端口三者中有一個不一樣即被稱做跨域。javascript
那麼爲何會有跨域呢?那要從同源提及。html
兩個 url 的域名、協議、端口都相同,稱爲兩個 url 同源。 同源是瀏覽器的安全限制,默認只有同源的兩個網站才能互相獲取數據。 若是沒有同源限制,不一樣網站之間能夠共享 cookie,攻擊者能夠直接獲取 cookie 發起 CSRF(跨站請求僞造)攻擊;接口隨便調用,致使數據泄漏或被刪。前端
跨域的解決方案有:script 等標籤、JSONP、iframe、node 請求轉發、CORS、nginx 反向代理等java
img、link、script 標籤經過 src 或 href 屬性支持訪問跨域資源,一般爲 cdn 資源、第三方包資源。node
<img src="xxx" />
<link href="xxx" />
<script src="xxx"></script>
複製代碼
jsonp 算是 script 標籤跨域的一種變體,經過在 script 標籤的 src 屬性後面加上 callback 字段實現跨域請求數據。webpack
<script> function getMenuData(data) { // 根據data渲染菜單 } </script>
<script src="http://www.a.com/data?callback=getMenuData"></script>
複製代碼
MenuData({ status: "success", data: ["menu1", "menu2"] });
複製代碼
客戶端和服務端在開發階段作好數據約定,因爲它僅支持 get 請求,如今使用場景已經不多了。nginx
iframe 的 postMessage 方法 自然支持跨域通訊,iframe 內外的頁面能夠採用不一樣源的 url。web
<iframe src="www.b.com" ><iframe>
<script> window.addEventListener("message", function (event) { console.log(event.data); }); </script></iframe
></iframe
>
複製代碼
window.postMessage(message, "http://www.a.com");
複製代碼
使用 nodejs 建立一個 中轉 server, 請求經過訪問 node server 轉發到目標地址, 突破跨域限制。 從一開始的:ajax
A => C A請求C
A <= C C響應A
複製代碼
轉變爲:json
A => B => C A請求B,B請求C
A <= B <= C C響應B,B響應A
複製代碼
var koa = require("koa");
var proxy = require("koa-proxy");
var app = koa();
app.use(
proxy({
host: "http://www.a.com", // 最終訪問的api地址
})
);
app.listen(3000);
複製代碼
tips:同源策略是瀏覽器的限制,不是服務器的限制。 此方法經常使用於開發時,後端不提供跨域支持,由前端解決跨域限制。如今 webpack-dev-server 自帶 proxy,再也不須要本身啓動額外的 server,只用添加配置就行,以下:
'/api': {
target: 'https://http://123.123.123.1:8080',
changeOrigin: true,
secure: false,
pathRewrite: {
'^/api': '/api'
}
}
複製代碼
cors 是服務端配置,配置跨域資源請求以後,服務端資源可被跨域請求。主要爲如下幾個響應頭:
值得注意得是,服務端設置了 CORS 以後須要針對 options 方法的請求作單獨處理。
options 請求是瀏覽器主動泛起的一個刺探請求。 發送簡單請求時瀏覽器不會生成刺探請求,發送複雜請求時會先發送一個嗅探請求,請求方法爲 options,待刺探請求成功返回後才發送真正的請求。 嗅探請求的做用是:提早將實際請求所使用的方法和會攜帶的首部字段發送給服務器,防止對服務器數據產生反作用。 options 請求產生的請求頭
origin: http://www.client.com
Access-Control-Allow-Methods: put...
Access-Control-Allow-Headers: Content-type...
複製代碼
簡單請求 知足如下條件的請求:
請求方法爲 HEAD、GET、POST 中的一種,
請求頭不超過如下幾個:
nginx 反向代理是指客戶端訪問服務器路徑 /api 地址時,服務器將 路徑/api 下的請求都代理到指定的服務下面,原理和借用 nodejs 實現請求轉發是同樣的。
location /api/ {
proxy_pass http://123.123.123.1:8080/api/;
index index.html index.htm;
}
複製代碼
跨域和同源其實不難,主要是要能結合理論解決平常遇到的問題:好比
Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource 你能很快定位問題是服務端沒有設置跨域致使的。
Mixed content: the page at 'www.xxx.com/' was loaded over HTTPS, but resquested an insecure prefetch resource 'www.ooo.com/'. This content should also be served over HTTPS 你能很快理解這是瀏覽器的安全限制。
是否是全部複雜請求都會發起 options 刺探請求?
不是的,options 請求能夠設置緩存時間,在過時以前不會再發刺探請求
Access-Control-Max-Age: time
複製代碼
關於瀏覽器安全限制、iframe父子頁面間通訊還有不少內容,歡迎評論、點贊。 此文章爲【js基礎】系列文章,關注小姐姐,一塊兒學一學!