如何克服 ReactJS 中的 CORS 问题

How to overcome the CORS issue in ReactJS

我正在尝试在我的 React 应用程序中通过 Axios 进行 API 调用。但是,我在浏览器上遇到了这个 CORS 问题。我想知道我是否可以从客户端解决这个问题,因为我在内部没有任何访问 API 的权限。附件是我的代码。

const response = axios({
  method: "post",
  dataType: "jsonp",
  url: "https://awww.api.com",
  data: {
    appToken: "",
    request: {
      applicationName: "ddfdf",
      userName: "jaime@dfd.com",
      password: "dfd",
      seasonIds: [1521ddfdfd5da02],
    },
  },
});

return {
  type: SHARE_REVIEW,
  payload: "response",
};

附上我的WebPack.config.js

module.exports = {
  entry: ["./src/index.js"],
  output: {
    path: __dirname,
    publicPath: "/",
    filename: "bundle.js",
  },
  module: {
    loaders: [
      {
        exclude: /node_modules/,
        loader: "babel",
        query: {
          presets: ["react", "es2015", "stage-1"],
        },
      },
      { test: /\.json$/, loader: "json-loader" },
    ],
  },
  resolve: {
    extensions: ["", ".js", ".jsx"],
  },
  devServer: {
    historyApiFallback: true,
    contentBase: "./",
  },
  node: {
    dns: "mock",
    net: "mock",
  },
};

理想的方法是为您的服务器添加 CORS 支持。

您也可以尝试使用单独的 jsonp 模块。据我所知axios不支持jsonp。所以我不确定您使用的方法是否符合有效的 jsonp 请求。

对于 CORS 问题,还有另一种骇人听闻的解决方法。您必须使用作为服务器和客户端代理的 nginx 服务器来部署代码。 proxy_pass 指令可以解决这个问题。配置您的 nginx 服务器,使处理您的特定请求的位置块 proxy_pass 或将您的请求重定向到您的实际服务器。 CORS 问题通常是由于网站域名发生变化而导致的。 当您使用单一代理作为客户端和服务器的界面时,浏览器会误认为服务器和客户端位于同一域中。因此没有 CORS。

考虑这个例子。

您的服务器是 my-server.com,您的客户端是 my-client.com 配置nginx如下:

// nginx.conf

upstream server {
    server my-server.com;
}

upstream client {
    server my-client.com;
}

server {
    listen 80;

    server_name my-website.com;
    access_log /path/to/access/log/access.log;
    error_log /path/to/error/log/error.log;

    location / {
        proxy_pass http://client;
    }

    location ~ /server/(?<section>.*) {
        rewrite ^/server/(.*)$ / break;
        proxy_pass http://server;
    }
}

此处 my-website.com 将是可访问代码的网站的最终名称(代理网站的名称)。 以这种方式配置 nginx 后。您将需要修改请求,以便:

  • 所有 API 调用从 my-server.com/<API-path> 变为 my-website.com/server/<API-path>

如果您不熟悉 nginx,我建议您阅读 documentation

简要解释上面的配置中发生了什么:

  • upstream 定义请求将重定向到的实际服务器
  • server 块用于定义 nginx 服务器的实际行为。
  • 如果有多个服务器块,server_name 用于标识将用于处理当前请求的块。
  • error_logaccess_log 指令用于定义日志文件的位置(用于调试)
  • location 块定义了对不同类型请求的处理:
    1. 第一个位置块处理所有以 / 开头的请求,所有这些请求都重定向到客户端
    2. 第二个位置块处理所有以 /server/<API-path> 开头的请求。我们会将所有此类请求重定向到服务器。

注意:/server这里用来区分客户端请求和服务器端请求。由于域相同,因此没有其他方法可以区分请求。请记住,没有这样的约定迫使您在所有此类用例中添加 /server 。它可以更改为任何其他字符串,例如。 /my-server/<API-path>/abc/<API-path>

尽管这种技术应该可以解决问题,但我强烈建议您向服务器添加 CORS 支持,因为这是处理此类情况的理想方式。

如果您希望在开发过程中避免执行所有这些操作,您可以使用 this chrome 扩展。它应该允许您在开发期间执行跨域请求。

通过名为 CORS 的 chrome 插件暂时解决了这个问题。顺便说一下,后端服务器必须向前端请求发送正确的 header。

除了@Nahush的答案之外的另一种方式,如果你已经在项目中使用Express框架那么你可以避免使用Nginx用于反向代理。

更简单的方法是使用 express-http-proxy

  1. 运行 npm run build 创建捆绑包。

    var proxy = require('express-http-proxy');
    
    var app = require('express')();
    
    //define the path of build
    
    var staticFilesPath = path.resolve(__dirname, '..', 'build');
    
    app.use(express.static(staticFilesPath));
    
    app.use('/api/api-server', proxy('www.api-server.com'));
    

使用 React 代码中的“/api/api-server”来调用 API。

So, that browser will send request to the same host which will be internally redirecting the request to another server and the browser will feel that It is coming from the same origin ;)

您可以使用 http-proxy-middleware 设置快速代理服务器来绕过 CORS:

const express = require('express');
const proxy = require('http-proxy-middleware');
const path = require('path');
const port = process.env.PORT || 8080;
const app = express();

app.use(express.static(__dirname));
app.use('/proxy', proxy({
    pathRewrite: {
       '^/proxy/': '/'
    },
    target: 'https://server.com',
    secure: false
}));

app.get('*', (req, res) => {
   res.sendFile(path.resolve(__dirname, 'index.html'));
});

app.listen(port);
console.log('Server started');

从您的 React 应用程序中,所有请求都应发送到 /proxy 端点,它们将被重定向到预期的服务器。

const URL = `/proxy/${PATH}`;
return axios.get(URL);

我从 "TraversyMedia" 的教程中找到的最简单的方法是 只需在 'axios' 或 'fetch' api

中使用 https://cors-anywhere.herokuapp.com
https://cors-anywhere.herokuapp.com/{type_your_url_here} 

例如

axios.get(`https://cors-anywhere.herokuapp.com/https://www.api.com/`)

在您的情况下,将 url 编辑为

url: 'https://cors-anywhere.herokuapp.com/https://www.api.com',

您可以让 React 开发服务器将您的请求代理到该服务器。只需像这样将您的请求发送到本地服务器:url: "/" 并将以下行添加到您的 package.json 文件

"proxy": "https://awww.api.com"

不过,如果您向多个来源发送 CORS 请求,则必须自己手动配置代理 link 将帮助您进行设置 Create React App Proxying API requests

正如@Nahush 已经指出的,这实际上是一个服务器问题,而不是应该在客户端处理的问题。服务器应该为 Access-Control-Allow-Origin: 添加 headers 参考 - https://www.w3.org/wiki/CORS_Enabled#How_can_I_participate.3F

在这里,如果您的服务器使用 express 框架,我只是在服务器端添加一种更简单的方法来执行此操作。使用 express CORS Middleware 是一个 2 行代码解决方案。

使用-

安装

npm install -S cors

将以下代码添加到您的后端应用。

import cors from 'cors';
app.use(cors());

完成。

您的服务器端代码一定缺少 Cors 支持。在 Asp.net 核心中,您可以按照以下方式进行。 在 public void ConfigureServices(IServiceCollection services) 中添加以下调用 在 Startup.cs 文件中。

public void ConfigureServices(IServiceCollection services)
{
     app.UseCors(options => 
                options.WithOrigins("http://localhost:3000").AllowAnyHeader().AllowAnyMethod());
}
        

我确实使用了 2 种解决方案来处理它:

  1. 使用http-proxy-middleware。但是,请按照以下视频步骤操作,而不是阅读我的图书馆 https://youtu.be/4B5WgTiKIOY(如果您也使用此解决方案,我确实提到了弱点)
  2. 使用Firebase functions创建中间件,不要太复杂。我也会在这里更新细节。

如有任何问题,请告诉我。

我遇到了问题,我在开发环境 (localhost) 中,所以我的客户端和服务器来源不同...

  • 所以最后我通过编写一个在本地主机上运行的简单自定义代理服务器克服了这个问题,(因为我无法访问服务器代码,我需要允许来自响应源的 cors)

在 localhost:3001:

上运行的简单代理服务器
const express = require("express");
const { createProxyMiddleware } = require("http-proxy-middleware");
var cors = require("cors");

const app = express();
const corsOptions = {
  //   origin: ["http://localhost:3000"],
  origin: true,
  credentials: true,
};
app.use(cors(corsOptions));

const proxyMiddleware = createProxyMiddleware("/", {
  target: "https://....api origin.....com",
  changeOrigin: true,
});

app.use(proxyMiddleware);

app.listen(3001, () => {
  console.log("proxy is listening on port 3001");
});
  • 请注意,我的 React 应用程序 运行 在端口 3000 上,我的代理服务器在端口 3001
  • 因为我们在请求中使用了凭据,所以我们还需要将 origin 设置为我们应用程序的白名单来源,否则 cors 会将“Access-Control-Allow-Origin”设置为“*”,这会导致在浏览器中安全错误。

反应示例登录 post 通过我的代理请求:

      axios.post("http://localhost:3001/Login", dataToPost, { withCredentials: true })
      .then((res) => {
        if (res.status === 200) {
          //all cookies are set in you're browser
          console.log(res);
        }
      })
      .catch((err) => {
        console.log(err);
      });

如果您尝试执行诸如获取第 3 方 api 之类的操作,并且您从 client-side 收到 CORS 错误,您可以尝试使用此扩展程序:

允许 CORS:Access-Control-Allow-Origin

chrome:https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf

对于 mozilla:https://addons.mozilla.org/pt-BR/firefox/addon/access-control-allow-origin/