动态

详情 返回 返回

談談跨域那些事 - 动态 详情

瀏覽器中的HTTP請求

XMLHttpRequest

XHR對象用於與服務器交互。通過XMLHttpRequest可以在不刷新頁面的情況下請求特定URL,獲取數據。
XMLHttpRequestAJAX編程中被大量使用。

MDN文檔

Fetch

Fetch API提供了一個獲取資源的接口(包括跨域請求)

MDN文檔

AJAX

Asynchronous JavaScript And XML,是一種使用XMLHttpRequest技術構建更復雜,動態的網頁的編程實踐。大部分的ajax其實就是對XMLHttpRequest的相關API進行封裝,使其使用起來更加方便。

MDN文檔

跨域

跨域,顧名思義,跨越區域。大概意思為訪問的網站請求非同源資源。

當前頁面URL 被請求資源URL 跨域 原因
http://www.test.com http://www.test.com/api/users 同源(協議 域名 端口號相同)
http://www.test.com https://www.test.com/api/users 協議不同(http/https)
http://www.test.com http://www.baidu.com/api/users 主域名不同(test/baidu)
http://www.test.com http://blog.test.com/api/users 子域名不同(www/blog)
http://www.test.com:8080 http://www.test.com:7070/api/... 端口號不同(8080/7070)

為什麼會有跨域

遇事先問為什麼。所以,瀏覽器為什麼要設置跨域的限制,然後我們後面還要費心費力地消除跨域的限制。

為了web生態的安全。看一個例子:

假設瀏覽器裏面的代碼可以隨意訪問第三方的數據(非同源),那麼你可以讓你的代碼定時輪詢訪問一個非同源的網頁,假設某個時刻恰好有10萬人在訪問你的網頁,那這個第三方的網頁每秒就要承受10萬的併發量,這樣網絡中大量的帶寬就會被這樣白白的浪費掉,整個web生態將會混亂無比。

當訪問的網站需要請求非同源資源時,瀏覽器將拒絕這些非同源請求。在這種情況下,我們需要解決瀏覽器跨域時拒絕請求非同源資源的限制。

當瀏覽器出現跨域時,那就不可避免的引出兩個關鍵的概念了。簡單請求非簡單請求

當跨域產生時,非簡單請求會在真正向服務端發送請求前進行預檢請求(OPTIONS),。

簡單請求

1、條件定義:若請求滿足以下所有的條件,則請求可視為簡單請求

  • 使用下列方法之一:
  • GET
  • HEAD
  • POST
  • 請求首部字段不得超出以下集合
  • Accept
  • Accept-Language
  • Content-Language
  • Conent-Type:text/plain || multipart/form-data || application/x-www-form-urlencoded
  • DPR
  • Downlink
  • Save-Data
  • Viewport-Width
  • Width
  • 請求中的任意XMLHttpRequestUpload 對象均沒有註冊任何事件監聽器
  • 請求中沒有使用 ReadableStream 對象

非簡單請求

1、條件定義:若請求滿足下列任一條件時,即應首先發送預檢請求(options)。

  • 使用了下面的任一方法:
  • PUT
  • DELETE
  • CONNECT
  • OPTIONS
  • TRACE
  • PATCH
  • 設置了額外的請求首部字段(除去以下集合中的)
  • Accept
  • Accept-Language
  • Content-Language
  • Conent-Type:text/plain || multipart/form-data || application/x-www-form-urlencoded
  • DPR
  • Downlink
  • Save-Data
  • Viewport-Width
  • Width
  • 請求中的XMLHttpRequestUpload 對象註冊了任意多個事件監聽器
  • 請求中使用了ReadableStream對象

解決跨域的方案

jsonp

JSON with Padding,是JSON的一種使用模式,可以讓網頁從別的網域獲取資料。由於同源策略,一般來説位於server1.example.com的網頁無法與不是server1.example.com的服務器溝通,而HTML的<script>元素是一個例外。利用<script>元素的這個開放策略,網頁就可以實現跨域獲取後端接口數據。

由於使用script標籤的src屬性,因此只支持get方法

當使用JSONP這種方案時,前後端都要有相對應的寫法。
大致流程就是,前端通過<script>標籤的src屬性向後台接口發起請求(只支持GET請求),並且傳遞參數callback='response',與此同時,前端必須定義函數response(responseData),這是用來處理接口返回數據後一些操作。
當接口收到請求,返回數據格式為response(responseData)。這樣,當前端接受到數據response(responseData),就剛好執行了我們已經定義好的response(...)

當報錯如下時:

原因是:後端接口沒有返回callback(...)

維基百科

JSONP的原理和實現

CORS

Cross Origin Resource Sharing,跨域資源共享,由一系列傳輸的HTTP頭組成,這些HTTP頭決定瀏覽器是否阻止前端JavaScript代碼獲取跨域請求的響應。

MDN文檔

1、Access-Control-Allow-Origin:指示請求的資源能共享給哪些域

2、Access-Control-Allow-Credentials:指示當請求的憑證標記為true時,是否響應該請求

3、Access-Control-Allow-Headers:用在對預請求的響應中,哪些HTTP方法允許訪問請求的資源

4、Access-Control-Expose-Headers:指示哪些HTTP頭的名稱能在響應中列出

5、Access-Control-Max-Age:指示預請求的結果能被緩存多久

6、Access-Control-Request-Headers:用於發起一個預請求,告知服務器正式請求會使用哪些HTTP頭

7、Access-Control-Request-Method:用於發起一個預請求,告知服務器正式請求會使用哪一種HTTP請求方法

8、Origin:指示獲取資源的請求是從什麼域發起的

koa2中接口允許跨域響應,響應頭部字段設置如下:

ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT');
ctx.set('Access-Control-Allow-Headers', 'X-Requested-With, User-Agent, Referer, Content-Type, Cache-Control,accesstoken');  
ctx.set('Access-Control-Max-Age', '86400');
ctx.set('Access-Control-Allow-Credentials', 'true');

注意事項
若添加了自定義的Header字段,必須將這個字段名添加到服務端響應頭部Access-Control-Allow-Headers中,不然會報錯。

項目踩坑
在接口響應中添加了以上允許跨域響應的頭部字段,但是在開發中還報了跨域的錯誤(Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request),報錯的大致意思是預檢請求禁止重定向。經過排查,發現是服務端nginx做了HTTP到HTTPS的重定向設置,而我恰好是以http+ip地址的形式發起請求的,那麼請求就被重定向到https了,然而,瀏覽器發起的預檢請求是禁止重定向的,因此報錯了。解決方案就是將請求地址改為https+域名的形式,這樣預檢請求就不會重定向了。

Add a new 评论

Some HTML is okay.