談談跨域那些事

瀏覽器中的HTTP請求

XMLHttpRequest

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

MDN文檔nginx

Fetch

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

MDN文檔編程

AJAX

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

MDN文檔segmentfault

跨域

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

因爲安全性等問題,瀏覽器自帶同源策略,所謂同源是指域名,協議,端口均相同。當訪問的網站須要請求非同源資源時,瀏覽器將拒絕這些非同源請求。在這種狀況下,咱們須要解決瀏覽器跨域時拒絕請求非同源資源的限制。跨域

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

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

簡單請求

一、條件定義:若請求知足如下全部的條件,則請求可視爲簡單請求

  • 使用下列方法之一:
  • 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 對象

非簡單請求

一、條件定義:若請求知足下列任一條件時,即應首先發送預檢請求(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文檔

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

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

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

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

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

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

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

八、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+域名的形式,這樣預檢請求就不會重定向了。

相關文章
相關標籤/搜索