Web高級 Ajax和跨域CORS

Asynchronous JavaScript and XML

1. XMLHttpRequest

前端開發都知道,很少說。javascript

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
    if (xhr.readyState !== 4) return;
    if (xhr.status >= 200 && xhr.status < 300) {
        console.log(JSON.parse(xhr.responseText));
    }
    else {
        // What to do when the request has failed
        console.log('error', xhr);
    }
};
xhr.open('GET', 'https://mysite.com/index');
xhr.setRequestHeader('X-Token', '123456'); 
xhr.send();

1.1 open方法

定義:open( Method, URL, Asynchronous, UserName, Password )
- Method:GET/POST/HEAD/PUT/DELETE/OPTIONS
- Asynchronous(defualt true)html

1.2 setRequestHeader方法

定義:setRequestHeader( Name, Value )
注意,以X開頭的爲header爲自定義頭部前端

1.3 send方法

定義:send(body)java

  • body能夠是:document,Blob, BufferSource, FormData, URLSearchParams, ReadableStream等

2. Fetch

新一代旨在替換XHR的API方法。json

fetch("https://mysite.com/index", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
    'X-Token': '123456'
  },
  body: "id=123"
}).then(function (response) {
    if (response.ok) {
        return response.json();
    } else {
        return Promise.reject({
            status: response.status,
            statusText: response.statusText
        });
    }
})
.then(function (data) {
    console.log('success', data);
})
.catch(function (error) {
    console.log('error', error);
});

2.1 fetch方法

定義:fetch(input, init)api

  • input:URL或者Request對象
  • init:一個配置項對象,包括全部對請求的設置。可選的參數有:
    • method: 請求使用的方法,如 GET、POST。
    • headers: 請求的頭信息,形式爲 Headers 對象或 ByteString。
    • body: 請求的 body 信息:多是一個 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 對象。注意 GET 或 HEAD 方法的請求不能包含 body 信息。
    • mode: 請求的模式,如 cors、 no-cors 或者 same-origin。
    • credentials: 請求的 credentials,如 omit、same-origin 或者 include。
    • cache: 請求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached.

2.2 回調

fetch返回一個promise,採用then的鏈式調用避免回調地獄問題。跨域

2.3 返回值

參考這裏:https://developer.mozilla.org/zh-CN/docs/Web/API/Responsepromise

3. XHR vs Fetch

  1. Fetch返回值不是可讀的形式,須要使用response.json()轉換爲可讀形式
  2. XHR的請求失敗經過判斷狀態碼,Fetch請求失敗經過catch處理
  3. Fetch默認不帶cookie,XHR默認帶cookie
  4. Fetch在服務器返回 400,500 錯誤碼時並不會reject而被當作成功處理進then,只有網絡錯誤這些致使請求不能完成纔會觸發catch
  5. Fetch沒有abort和onTimeout,不能中途中斷,XHR能夠。

Cross-Origin Resource Sharing

CORS是一種機制,用來保護跨域數據傳輸的安全性和下降風險。瀏覽器

1. 常見的能夠跨域請求的資源

  • XHR或Fetch發起的跨域HTTP請求
  • Web字體
  • CSS文件
  • Scripts文件

2. 跨域相關的Http首部

  • Access-Control-Request-Headers
    (Preflight使用)客戶端告訴服務器實際請求時使用的頭部。
  • Access-Control-Request-Method
    (Preflight使用)客戶端告訴服務器實際請求時使用的方法。緩存

  • Access-Control-Allow-Origin
    服務端容許請求的源域
  • Access-Control-Allow-Credentials
    服務端是否容許請求帶cookie,設置爲true時allow-origin不能爲*
  • Access-Control-Allow-Headers
    服務端容許的客戶端請求的頭部
  • Access-Control-Allow-Methods
    服務端容許客戶端請求的方法
  • Access-Control-Max-Age
    preflight能夠被緩存的時間
  • Cross-Origin-Resource-Policy
    (fetch使用)具體查看https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header
  • Origin
    客戶端請求從哪一個域來

1. OPTIONS /resources/post-here/ 
2. HTTP/1.1
3. Host: bar.other
4. User-Agent: Mozilla/5.0 (Macintosh; U; 5.Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
6. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
7. Accept-Language: en-us,en;q=0.5
8. Accept-Encoding: gzip,deflate
9. Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
10. Connection: keep-alive
11. Origin: http://foo.example
12. Access-Control-Request-Method: POST
13. Access-Control-Request-Headers: X-PINGOTHER, Content-Type

//響應
14. HTTP/1.1 200 OK
15. Date: Mon, 01 Dec 2008 01:15:39 GMT
16. Server: Apache/2.0.61 (Unix)
17. Access-Control-Allow-Origin: http://foo.example
18. Access-Control-Allow-Methods: POST, GET, OPTIONS
19. Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
20. Access-Control-Max-Age: 86400
21. Vary: Accept-Encoding, Origin
22. Content-Encoding: gzip
23. Content-Length: 0
24. Keep-Alive: timeout=2, max=100
25. Connection: Keep-Alive
26. Content-Type: text/plain

3. 簡單請求

跨域請求分爲簡單請求和預檢請求,所有符合下列條件時爲簡單請求:

  • 使用的方法爲:GET/HEAD/POST
  • 不得設置安全首頁以外的首頁:Accept,Accept-Language,Content-Language,Content-Type,DPR,Downlink,Save-Data,Viewport-Width,Width
  • Content-Type只能是如下值: text/plain, multipart/form-data, application/x-www-form-urlencoded
  • 請求中的任意XMLHttpRequestUpload 對象均沒有註冊任何事件監聽器
  • 請求中沒有使用 ReadableStream 對象

當使用普通請求時,若是服務器容許該源域跨域請求資源,則直接返回響應。若是服務器不容許跨域請求,則返回不正確的響應首部,則請求方不會收到任何數據。

4. 預檢請求(preflight request)

除了簡單請求的狀況,其餘的CORS請求都會有預檢請求。
預檢請求會先使用OPTIONS方法發起一個預檢請求到服務器,以獲知服務器是否容許該實際請求,因此會進行2個回合的通訊。

典型的會觸發預檢請求的跨域情景:請求JSON數據 或 帶有自定義頭部
如:

  • content-type:application/json
  • X-Audit-Token:X123456

JSONP

跨域請求的一種常見實現方式.

1. 優缺點

  • 優勢:
    不受同源策略限制,能夠向沒有啓用CORS的跨域服務端請求數據。
    兼容性較強,全部瀏覽器都支持該技術。
  • 缺點
    只支持GET,不支持POST
    請求失敗時不會有HTTP狀態碼返回
    安全性也是一個值得考慮的問題

2. 實現原理

  1. Client端用JS動態生成一個script標籤並添加到文檔流中,如
<script type="text/javascript">
  function jsonpCallBack(data){
        console.log(data.msg);
  }
  $(document).ready(function(){
        $("body").append('<script src="http://www.ASite.com/ServerJSONP.js?callback=jsonpCallBack"></script>');
    });
</script>
  1. 瀏覽器會使用GET方法請求ASite上的ServerJSONP.js並攜帶參數
  2. 服務端接收到該請求,並根據參數中的回調函數名動態生成返回的內容,如
jsonpCallBack({msg:"this is jsonp request!"});
  1. 瀏覽器獲取到script標籤請求的內容後會執行其中的代碼
  2. 最終咱們定義的jsonpCallBack函數會被調用,輸出: "this is jsonp request!"

refs:
https://xhr.spec.whatwg.org/
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
https://gomakethings.com/why-i-still-use-xhr-instead-of-the-fetch-api/
https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

相關文章
相關標籤/搜索