Совместное использование ресурсов между источниками — CORS

внешний интерфейс сервер программист JavaScript

Совместное использование ресурсов между источниками — это механизм, который использует дополнительные заголовки HTTP, чтобы сообщить браузеру, что веб-приложение может выполнять запросы ресурсов из разных источников.

тип запроса

простой запрос

если запросУдовлетворить всем следующим условиям одновременно, запрос можно рассматривать как "простой запрос"(Примечание: содержимое серого шрифта можно понять):

  • Используемый метод
    • GET
    • HEAD
    • POST
  • Поля заголовков, заданные вручную, могут быть только (Примечание: также могут быть установленыForbidden header nameполя заголовка вConnection,Accept-Encodingд., но настройка не влияет)
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type(Диапазон значений также должен соответствовать следующим требованиям)
    • `DPR`
    • `Downlink`
    • `Save-Data`
    • `Viewpoer-Width`
    • `Width`
  • Content-TypeЗначение может быть только
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain
  • No event listeners are registered on any `XMLHttpRequestUpload` object used in the request; these are accessed using the XMLHttpRequest.upload property.
  • No ReadableStream object is used in the request.

предварительный запрос

Запрос предварительной проверки CORS выполняется перед фактическим запросом и используется для проверки того, поддерживает ли сервер CORS, чтобы определить, безопасно ли отправлять фактический запрос. Предварительный запрос используется следующим образом:OPTIONS.

Если запрос не является «простым запросом», сначала следует отправить предварительный запрос, например:

  • Метод запроса для этого запроса неGET,HEAD,POST
  • В качестве альтернативы запрос устанавливает настраиваемые поля заголовка, такие какX-xxx
  • или этот запросContent-Typeзначение неapplication/x-www-form-urlencoded,multipart/form-data,text/plain,так далее

Процесс запроса между источниками

Для междоменных запросов CORS требует, чтобы сервер установил некоторые поля заголовка, наиболее важным из которых являетсяAccess-Control-Allow-Origin. Ниже приведен пример, иллюстрирующий использование внешнего интерфейса.axiosДля передачи http серверная часть начинается сkoaВ качестве серверной среды и использования промежуточного программного обеспечения CORS.koa2-cors.

Простой междоменный запрос

// Client http://localhost:8080
simpleRequest() {
  axios({
    method: 'GET',
    url: 'http://localhost:3000/api/simple'
  }).then(data => {
    console.log(data);
  });
}
// Server http://localhost:3000
app.use(cors());
router.get('/api/simple', ctx => {
  ctx.body = { result: 'simple request success' };
});

HTTP-сообщение:

Заголовок HTTP-запроса имеетOriginПоле, указывающее, откуда пришел запрос. в заголовке ответа HTTPAccess-Control-Allow-OriginУказывает, какой домен может получить доступ к ресурсу. использоватьOriginа такжеAccess-Control-Allow-OriginНа этом простейший контроль доступа завершен.

Предварительный запрос и официальный запрос

// Client http://localhost:8080
mainRequest() {
  axios({
    method: 'POST',
    url: 'http://localhost:3000/api/mainRequest',
    headers: { 'X-test': 'CORS' } // 增加一个自定义的头部字段,触发预检请求
  }).then(data => {
    console.log(data);
  });
}
// Server http://localhost:3000
app.use(cors());
router.post('/api/mainRequest', ctx => {
  ctx.body = { result: 'main request success' };
});

Сообщение предполетного запроса:

поля заголовка запросаAccess-Control-Request-Methodсообщить серверу, что фактический запрос будет использоватьPOSTметод. поля заголовка запросаAccess-Control-Request-HeadersСообщите серверу, что фактический запрос будет содержать пользовательское поле заголовка запроса: x-test. На основании этого сервер решает, разрешен ли фактический запрос.

поля заголовка ответаAccess-Control-Allow-MethodsУказывает, какие методы сервер разрешает клиентам использовать для выполнения запросов. поля заголовка ответаAccess-Control-Allow-HeadersУказывает, что сервер разрешает перенос поля x-test в запросе.

Фактическое сообщение запроса:

отправлено в фактическом запросеX-testПоле заголовка, код состояния ответа 200 OK.

Видно, что клиент и сервер используют больше полей заголовка в предварительном запросе для полного контроля доступа. Итак, что такое поля заголовка запроса и поля заголовка ответа, связанные с CORS?

поле заголовка

Поля заголовка HTTP-запроса

  • Origin
    OriginПоле заголовка указывает происхождение запроса предварительной проверки или фактического запроса.
  • Access-Control-Request-Method
    Access-Control-Request-Methodполя заголовка используются дляпредварительный запрос. Его роль состоит в том, чтобы сообщить серверу, какой метод HTTP использовался для фактического запроса.
  • Access-Control-Request-Headers
    Access-Control-Request-Headersполя заголовка используются дляпредварительный запрос. Его роль состоит в том, чтобы сообщить серверу поля заголовка, содержащиеся в фактическом запросе.

Обратите внимание, что приведенные выше поля заголовка запроса не нужно задавать вручную при использованииXMLHttpRequestКогда объекты делают запросы между источниками, они уже настроены.

Поля заголовка ответа HTTP

  • Access-Control-Allow-Origin
    Его синтаксис следующий:

    Access-Control-Allow-Origin: <origin> | *  
    

    Значение параметра origin указывает URI внешнего домена, которому разрешен доступ к ресурсу. Если значение поля является подстановочным знаком*, что означает, что запросы от всех доменов разрешены.
    Обратите внимание, что если сервер указывает конкретное доменное имя вместо*, то заголовок ответаVaryЗначение поля должно содержатьOrigin. Это сообщит клиенту: сервер возвращает разный контент для разных источников.

  • Access-Control-Allow-Methods
    Access-Control-Allow-MethodsПоля заголовка используются для ответов на предварительные запросы. Он указывает методы HTTP, разрешенные для фактического запроса.

  • Access-Control-Allow-Headers
    Access-Control-Allow-HeadersПоля заголовка используются для ответов на предварительные запросы. Он определяет поля заголовка, которые разрешено использовать в фактическом запросе.

  • Access-Control-Expose-Headers
    В запросе из другого источника браузер по умолчанию может получить через API только следующие поля заголовка ответа:

    • Cache-Control
    • Content-Language
    • Content-Type
    • Expires
    • Last-Modified
    • Pragma

    Если вы хотите получить доступ к другой информации заголовка ответа, вам необходимо установить ее на стороне сервера.Access-Control-Allow-Headers.Access-Control-Expose-HeadersПусть сервер внесет в белый список поля заголовков, к которым разрешен доступ браузерам, например:

    Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
    

    Браузер может получить доступX-My-Custom-Headerа такжеX-Another-Custom-Headerзаголовки ответов.

  • Access-Control-Max-Age
    Access-Control-Max-AgeПоле указывает, как долго результаты предварительного запроса могут кэшироваться, в единицахВторой,Например:

    Access-Control-Max-Age: 5
    

    Указывает, что после отправки первого запроса предварительной проверки фактический запрос будет отправлен непосредственно при повторном доступе к интерфейсу в течение 5 с, без необходимости предварительной отправки запроса предварительной проверки. Через 5 секунд он попросит сначала отправить предварительный запрос и так далее.

    app.use(
      cors({
        maxAge: 5
      })
    );
    

    Сервер устанавливает 5-секундный кеш, и фактический запрос выглядит следующим образом:

    Обратите внимание: если вы обнаружите, что запрос OPTIONS по-прежнему отправляется каждый раз после настройки кеша, проверьте, не поставили ли вы флажок «Запретить кеширование».

  • Access-Control-Allow-Credentials
    XMLHttpRequest.withCredentials(илиRequest.credentials) указывает, должен ли пользовательский агент отправлять учетные данные, такие как файлы cookie, заголовки авторизации или сертификаты клиента TLS, в запросах между источниками.Access-Control-Allow-CredentialsФункция такова: когда учетные данные «истинны» (XHR и Fetch установлены по-разному),Access-Control-Allow-CredentialsСообщите браузеру, следует ли предоставлять содержимое ответа внешнему JS-коду. Например:

    // Client http://localhost:8080
    simpleRequest() {
      axios({
        method: 'GET',
        url: 'http://localhost:3000/api/simple',
        withCredentials: true // 增加了withCredentials 选项
      }).then(data => {
        console.log(data);
      });
    }  
    
    // Server http://localhost:3000
    app.use(
      cors({
        maxAge: 5,
        // credentials: true
      })
    );
    

    На данный момент сервер не установленcredentials: true, вы можете увидеть, как клиент сообщает об ошибке, когда вы инициируете запрос:

    Если сервер установленcredentials: trueТогда клиент не сообщит об ошибке.

    При предварительной проверке запросовAccess-Control-Allow-CredentialsПоле заголовка ответа указывает, можно ли использовать учетные данные в фактическом запросе.

Что касается использования полей заголовка ответа CORS, рекомендуется взглянутьkoa2-corsИсходный код промежуточного программного обеспечения. Код состоит всего из нескольких десятков строк, и он очень понятен и прост для понимания.


Соответствующее содержание CORS указано выше.После понимания это может лучше помочь нам решить проблемы при ежедневной совместной отладке, такие как: как настроить сервер при возникновении междоменного взаимодействия,axios.postПочему появляется запрос OPTIONS, когда метод отправляет объект, как прокси-сервер может пересылать куки и т.д.