預檢請求(preflight request)

我們先看看什麼是 預檢請求

A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood.

It is an OPTIONS request, using three HTTP request headers: Access-Control-Request-MethodAccess-Control-Request-Headers, and the Origin header.

A preflight request is automatically issued by a browser, when needed. In normal cases, front-end developers don't need to craft such requests themselves.

For example, a client might be asking a server if it would allow a DELETE request, before sending a DELETE request, by using a preflight request:

OPTIONS /resource/foo 
Access-Control-Request-Method: DELETE 
Access-Control-Request-Headers: origin, x-requested-with
Origin: https://foo.bar.org

If the server allows it, then it will respond to the preflight request with a Access-Control-Allow-Methods response header, which lists DELETE:

HTTP/1.1 200 OK
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: https://foo.bar.org
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400

簡單的來說就是,就是判斷CORS的協議是否被server端理解。

1)如果被理解,就是先發送一個OPTIONS請求。請求頭需包含以下三個字段

    Access-Control-Request-MethodAccess-Control-Request-Headers, and the Origin header.

 2)瀏覽器自動發出,不需要自己發出。

看完了,是不是一臉萌幣,什麼叫被服務器理解。那麼服務器又能理解哪些東西:

預先定義好的簡單請求頭。包含以下東西。

simple header (or CORS-safelisted request header) is one of the following HTTP headers:

Or one of these client hint headers:

When containing only simple headers, a requests is deemed simple and doesn't need to send a preflight request in the context of CORS.

最後一句話,如果是上面的請求頭,就被視爲一個簡單的請求,並不需要發預檢請求。也就是說OPTIONS請求不會發出。

現在情況明朗了。如果你使用自定義的請求頭,server自然無法理解。就需要發出OPTIONS請求。

下面給出一個例子:

客戶端:

      let promise = new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest(),
            url = "http://localhost:3000/data";
        xhr.onreadystatechange = () => {
          if(xhr.readyState === 4) {
            if(xhr.status === 200) {
              resolve(JSON.parse(xhr.responseText));
            } else {
              reject();
            }
          }
        }
        xhr.open("GET", url);
        xhr.setRequestHeader("x-token", "I am x-token"); // 包含自定義請求頭,服務器需要設置Access-Control-Allow-Headers
        xhr.send(null); // 會發出預檢請求。也就是OPTIONS請求
      });
      promise.then((data) => {
        console.log(data);
      });

服務端

var express = require("express"),
  app = express();

app.use((req, res, next) => {
  res.set("Access-Control-Allow-Origin", "http://localhost:8080");
  res.set("Access-Control-Allow-Headers", "x-token"); // 需要對客戶端進行同步設置
  next();
});

app.all("/message", (req, res) => {
  res.json({
    fruitList: ["apple", "banana", "coconut", "watermelon"]
  });
});

app.all("/data", (req, res) => {
  console.log(req.get("x-token"));
  res.json({
    name: "pizza",
    size: "medium"
  });
});

app.listen(3000, () => {
  console.log("server is running");
});


客戶端發送截圖:

第一發送: 會發送OPTIONS請求。包含以下三個字段。



第二次發出,會發出一個GET請求。


注意: 這裏和請求的類型是無關的,無論是GET請求或者是POST請求。

參考文章:

Simple Headers

OPTIONS

preflight request


寫完了,才發現推送了一個文章。暈,寫的很好,貼出

簡單跨域請求和帶預檢的跨域請求


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章