【问题标题】:Using Fetch API instead of Ajax for Allow-Credentials + POST requests使用 Fetch API 而不是 Ajax 处理 Allow-Credentials + POST 请求
【发布时间】:2018-09-17 15:45:27
【问题描述】:

此方案使用Access-Control-Allow-CredentialsPOST 方法来管理必须保持不变的服务器端PHP 会话变量。

作为参考,前端是在 http://localhost:3000 上运行的 create-react-app 项目,后端是在 example.com 上运行的 PHP

使用$.ajax() 方法实现这一点既简单又直接。

  UseAjax(incomingData) {
    return new Promise(function(resolve, reject) {
      $.ajax({
        url: 'http://example.com/api.php',
        type: 'post',
        data: incomingData,
        xhrFields: { withCredentials: true },
        success: function(data) {
          console.log(data)
        }
      })
      .then((data,status) => {
        // Get the result and transform into valid JSON
        if ( typeof data === typeof 'str' ) {
          try {
            data = JSON.parse(data);
          } catch(e) {
            reject(data,status);
            console.log('Exception: ', e);
            console.log('API Returned non-JSON result: ', data);
          }
        }
        return data;
      }).then((dataObject) => {
        console.log('dataObject:');
        console.log(dataObject);
        resolve(dataObject);
      });
    });
  }

但奇怪的是,当使用fetch() API 时,给人的印象是我不允许使用CORS。当然,我启用了CORS,因为此请求适用于Ajax,并且仅在使用fetch() API 时失败。

这是我在使用fetch() API 时尝试过的内容。

  UseFetch(requestData) {
    return new Promise(function(resolve, reject) {
      console.log('Relay() called with data: ', requestData);
      fetch('http://example.com/api.php', {
        method: 'POST', // or 'PUT'
        body: JSON.stringify(requestData), // data can be `string` or {object}!
        headers: new Headers({
          'Content-Type': 'application/json'
        })
      }).then((result) => {
        // Get the result
        return result.json();
      }).then((jsonResult) => {
        // Do something with the result
        if ( jsonResult.err )
          reject(jsonResult);
        console.log(jsonResult);
        resolve(jsonResult);
      });
    });
  }

它提供了这个错误。

Failed to load http://example.com/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

PHP 端,我使用简单的输出来确保没有其他问题会导致服务器端出现错误。

<?php
  header('Content-Type: application/json');
  header('Access-Control-Allow-Origin: http://example.com');
  header('Access-Control-Allow-Methods: POST');
  header('Access-Control-Allow-Headers: Content-Type, Authorization, x-requested-with');
  echo json_encode(['data'=>'result']);
?>

我关注了很多问题,但最值得注意的是this question with a very thorough explanation of the issue and possible solutions

目前,我只是使用久经考验的$.ajax() 来完成此任务,但我想在复制此功能所需的范围内完全理解fetch() API,因为它看起来非常根据我的经验基本。

【问题讨论】:

  • 您可能希望使用浏览器开发工具的“网络”窗格来查看两种情况($.ajax() 情况和fetch() 情况)的请求和响应的完整详细信息——包括完整的请求标头和请求方法以及响应标头和响应的 HTTP 状态代码 - 然后使用 stackoverflow.com/posts/49712690/edit 将这些详细信息粘贴到问题中。
  • 您的 $.ajax 代码和 fetch 代码之间有一个区别:在您的 fetch 代码中,您添加了一个额外的 ContentType 标头,该标头不是由 $.ajax 代码设置的,这将强制浏览器发送预检请求。您的 php 代码似乎没有以能够正确处理预检的方式编写。但是....您的错误消息与该问题不完全匹配。错误消息指出没有访问控制标头,这可能是由于 PHP 错误导致您的标准 500 错误页面没有 CORS 标头。

标签: php ajax reactjs cors fetch


【解决方案1】:

在您的 PHP 代码中,您指定了header('Access-Control-Allow-Origin: http://example.com');。这是错误的 - 您需要指定在 Origin 请求标头中传递的值(在您的情况下为 http://localhost:3000):

header('Access-Control-Allow-Origin: http://localhost:3000');

理想情况下,您不会对其进行硬编码 - 您只需提取 Origin 请求标头并将其传回即可。

顺便说一句,我相信 JQuery 的 $.Ajax 在幕后使用了 fetch()(就像 XmlHTTPRequest() 一样)。基本上,一切都使用 fetch...

【讨论】:

  • 鉴于收到的错误消息,我认为这不是当前问题,但在当前问题解决后可能是其中一个。当前的错误消息表明没有访问控制标头。如果有一个但来源不匹配,则错误消息会有所不同。
  • 正如@sideshowbarker 在他对您的原始帖子的评论中所建议的那样,您能否提供一套完整的请求和响应标头?啊,我看你不是OP。道歉。
  • 你对 jQuery api.jquery.com/Types/#jqXHR 的看法是错误的,它建立在 XMLHttpRequest 之上,Fetch 是一个全新的 API,建立在基础级别。它们都用于处理使用 HTTPS 或 HTTP 标准构建在 TCP/IP 上的请求。但那是用 C++ 构建的代码,在使用它们时,它们是完全独立的东西,彼此不依赖,因为 XMLHttpRequest 是第一个。如果他们要在此基础上构建,他们将在此基础上构建,而不是重新构建 XMLHttpRequest 以使用 fetch API 的代码。这只是浪费时间。
  • Martin,你说得对,fetch 和 XMLHttpRequest 是不同的。我错了——出于某种原因,我认为 XHR 已被重建以使用 fetch。尽管如此,否决我的(否则可能是正确的)答案似乎有点苛刻,不是吗?即使它没有回答完整的问题,事实是响应标头的编码不正确。叹息。
猜你喜欢
  • 2017-11-09
  • 2017-06-23
  • 1970-01-01
  • 2020-11-27
  • 2016-11-28
  • 2018-02-09
  • 1970-01-01
  • 2020-11-12
  • 1970-01-01
相关资源
最近更新 更多