预检请求(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


写完了,才发现推送了一个文章。晕,写的很好,贴出

简单跨域请求和带预检的跨域请求


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