使用 create-react-app 和 webpack 发出 CORS API 请求 - 不明确

Posted

技术标签:

【中文标题】使用 create-react-app 和 webpack 发出 CORS API 请求 - 不明确【英文标题】:Making CORS API requests with create-react-app and webpack - no express 【发布时间】:2018-10-05 03:03:30 【问题描述】:

我正在尝试在不禁用浏览器中的 CORS 的情况下进行 API 调用。该应用程序是使用 react-create-app 创建的。它使用 webpack 和 webpackDevServer 进行开发。我在这里找到的所有答案都说将以下代码放入我的webpack.config 文件中。

devServer: 
      headers: 
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
        "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
      
  

但是,我已经在许多不同的地方尝试过,但它不起作用。

我继续收到错误:

加载资源失败:服务器响应状态为500()

加载失败...对预检请求的响应未通过访问 控制检查:不存在“Access-Control-Allow-Origin”标头 请求的资源。因此,原点 'http://localhost:3000' 是 不允许访问。响应的 HTTP 状态代码为 500。

我还尝试将我的调用从 axios 调用更改为 fetch 调用

return fetch(process.env.REACT_APP_API_URL + "/prod/user", 
    mode: 'no-cors',
    credentials: 'include',
    method: "GET",
    headers: 
        "x-api-key": process.env.REACT_APP_API_KEY
    
)
.then(response => 
   return response.json()
)
.then(resp => dispatch(receiveUsers(resp.data)))
.catch(error => console.log(error))

这让我更接近了,但控制台现在正在返回

Response type: "opaque", url: "", redirected: false, status: 0, ok: false, …

如何解决这个 CORS 问题?提前感谢您的帮助!

Response/Request Headers

【问题讨论】:

好吧,CORS 是一种安全功能,理想情况下,不应避免使用它。您有权访问 API 源代码吗?如果是,您需要允许您正在开发的 URL。 Origin 'http://localhost:3000' is therefore not allowed access.这些,所以添加localhostlocalhost:3000。如果您没有访问权限,则需要代理请求。 【参考方案1】:

还不能添加评论,所以我会把它作为答案。

如果您尝试访问由其他节点应用程序或其他主机提供的 API。您可以配置 webpack-dev-server 将该请求代理到真实服务器。

查看Create React App Doc: Proxying API Requests in Development了解更多详情。

【讨论】:

链接已更改。新的是:facebook.github.io/create-react-app/docs/… 我遇到了同样的问题,这个代理路由是迄今为止最简单的。在您的 package.json 中只需一行(例如“proxy”:“localhost:8090")即可在 DEV 模式下(npm start)路由到另一台主机以进行 API 调用。【参考方案2】:

您看到对预检 OPTIONS 请求的 500 响应这一事实让我认为 Web 服务器可能根本不允许使用 OPTIONS 请求方法。

许多网络服务器默认只允许 HEAD、GET 和 POST,所以这是我要检查的第一件事。

如果这没有帮助,请确保上面的 webpack.config 代码对所有请求(即 OPTIONS 和 GET/POST)运行。

如果这没有帮助,请将一整套请求和响应标头发布到 OPTIONS 和 GET 请求,然后让我们看看从那里开始。

【讨论】:

这很有帮助,谢谢。我正在调用的 API 实际上允许 *,并且我错误地调用了 POST 和 GET。最后,我必须将 POST 的内容类型指定为“application/x-www-form-urlencoded”,并将数据字符串化以发布到 API。所以现在我可以 GET 和 POST,但我的 PUT 请求被 CORS 捕获,因为它作为 OPTIONS 发送 - 返回 200 - 但未通过预检访问控制检查。我应该能够发出 PUT 请求,但我不确定它为什么不起作用。也许这与我使用 axios 提出请求的方式有关? 更正。 PUT 总是会让浏览器抛出一个预检 OPTIONS 请求。现在的问题是,为什么当 API 允许 CORS 时浏览器会阻止 PUT 请求。 PUT 请求将导致浏览器首先发送预检 OPTIONS 请求。如果您没有发送有效的 CORS 标头来响应该 OPTIONS 请求,那么浏览器甚至不会自己发出后续的 PUT 请求。您可以发布 OPTIONS 请求的请求/响应标头吗? 嘿,Rory,谢谢 - 我在原始帖子中添加了指向图片的链接。 好的,因此您需要在 OPTIONS 请求以及 PUT 请求中包含 CORS 响应标头。目前还没有发生这种情况。我怀疑您的 webpack.config 定义没有用于 OPTIONS 请求,但我不知道您的代码到底是什么。但我确实看到,现在您收到了 200 条 OPTIONS 请求的响应,所以自从您第一次发布问题以来,情况发生了变化。【参考方案3】:

最好的选择是使用代理,尤其是当您使用外部 API 或多个 API 时。 只需安装proxy-middleware 并创建文件src/setupProxy.js 并在文件中添加类似的代码:

const proxy = require('proxy-middleware');

module.exports = app => 
  // setup proxies
  // 1st api
  app.use("/etherscan", proxy("http://api.etherscan.io/api"));
  // 2nd api
  app.use("/cryptocompare", proxy("https://min-api.cryptocompare.com/data"));

  // Note: setupProxy is an express server so you can also override anything in the req or res before proxy them for example 
  app.use("/cryptocompare", (req,res,next) => 
     req.headers =  
        ...req.headers,
        "my-header":"my header value"
     
     return proxy("https://min-api.cryptocompare.com/data")(req,res,next);
  );

  app.use("/cryptocompare", proxy("https://min-api.cryptocompare.com/data"));


  // also it's better to use .env variables
  // const REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL = process.env;
  // app.use(REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL);      
;

对于您的 API,如果您可以从 .env 变量中获取基本 URL,例如:

const REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL = process.env;
const baseURL = REACT_APP_API_ETHERSCAN_PROXY || REACT_APP_API_ETHERSCAN_BASE_URL;

附加建议:您可以查看axios,而不是继续为每个 API 调用传递 process.env.REACT_APP_API_URL 和标头,您可以在其中创建具有默认属性的 API 实例,例如:

const 
  REACT_APP_API_ETHERSCAN_PROXY, 
  REACT_APP_API_ETHERSCAN_BASE_URL,
  REACT_APP_API_TIMEOUT,
  REACT_APP_API_ETHERSCAN_KEY
 = process.env;

export const etherscanAPI = axios.create(
  "baseURL": REACT_APP_API_ETHERSCAN_PROXY || REACT_APP_API_ETHERSCAN_BASE_URL,
  "timeout": parseInt(REACT_APP_API_TIMEOUT),
  "headers": 
    "X-Requested-With": "XMLHttpRequest"
  ,
  "params": 
    "apiKey": REACT_APP_API_ETHERSCAN_KEY
  
);

然后etherscanAPI.get("/whatever")

【讨论】:

如何在 setupProxy 中发送标头?

以上是关于使用 create-react-app 和 webpack 发出 CORS API 请求 - 不明确的主要内容,如果未能解决你的问题,请参考以下文章

如何调试从 create-react-app 创建的应用程序使用的本地打字稿模块

使用 create-react-app 构建开发/调试构建

如何让 create-react-app 使用 IP 连接到我的 api 服务器?

将 Create-React-App 部署到多个 URL

sh 用于将工作证书链接到create-react-app的脚本。允许您使用create-react-app和有效的SSL证书。

手摸手从零使用 React17 + TS4 + create-react-app 完成一个网站(收藏!)