【问题标题】:How to overcome the CORS issue in ReactJS如何克服 ReactJS 中的 CORS 问题
【发布时间】:2017-09-13 17:08:00
【问题描述】:

我正在尝试在我的 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,因为这会使 CORS 无关

标签: javascript reactjs cors redux axios


【解决方案1】:

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

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

还有另一个针对 CORS 问题的 hackish 解决方法。您必须使用 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/(.*)$ /$1 break;
        proxy_pass http://server;
    }
}

这里my-website.com 将是可访问代码的网站的结果名称(代理网站的名称)。 一旦以这种方式配置了 nginx。您将需要修改请求,以便:

  • 所有 API 调用都从 my-server.com/&lt;API-path&gt; 更改为 my-website.com/server/&lt;API-path&gt;

如果你不熟悉 nginx,我建议你通过documentation

简单解释一下上面的配置发生了什么:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 这就像一个魅力。如果您只是想测试并启动并运行某些东西,这真的很有帮助。我使用了 Moesif Origin & CORS Changer 插件。只需打开它,它就可以工作!
    【解决方案3】:

    除了@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。

    因此,该浏览器将向同一主机发送请求,该主机将 在内部将请求重定向到另一台服务器,浏览器会觉得它来自同一个来源;)

    【讨论】:

      【解决方案4】:

      您可以使用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);
      

      【讨论】:

      • 成功了。我对如何在我的服务中使用代理以及它的工作方式感到困惑。谢谢!
      • 这很有趣。所以这个代理服务器需要在前端 React 应用程序中运行?
      • @MarvinLazer 代理服务器需要在为您的 React 应用程序提供服务的同一服务器中运行。您可以查看此 repo 以获取工作示例 - github.com/HarshadRanganathan/gnib-visa-app。开发模式下的这个 repo 使用 express 代理服务器,而生产模式下使用 nginx 代理服务器,它也为静态反应文件提供服务。
      【解决方案5】:

      我从“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',
      

      【讨论】:

      • 天哪 #%$ 这成功了!我的日子有救了,你能解释一下这是做什么的吗?
      • CORS-Anywhere HerokuApp 提供了一个代理来传递我们的请求及其标头。您可以在cors-anywhere.herokuapp.com 上了解更多信息,更多解释请访问媒体的帖子-medium.com/netscape/…
      • 请注意,这会导致您的所有 API 请求都通过第三方应用程序,这绝对不是一个好的安全做法。
      • 这应该是我退出之前的最后一次搜索,我阅读了有关如何解决它的文章,但直到我看到你的解决方案才弄清楚如何。
      • Herokuapp "Cors Anywhere" 是一个演示,速度很慢,所以不能在生产应用程序上使用。
      【解决方案6】:

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

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

      虽然如果您向多个来源发送 CORS 请求,您必须自己手动配置代理 此链接将帮助您设置 Create React App Proxying API requests

      【讨论】:

      • 更详细的类似答案可以在here找到。
      【解决方案7】:

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

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

      安装使用 -

      npm install -S cors

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

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

      完成了。

      【讨论】:

        【解决方案8】:

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

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

        【讨论】:

          【解决方案9】:

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

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

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

          【讨论】:

            【解决方案10】:

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

            • 所以最后我通过编写一个在 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 端口上
            • 因为我们在我们的请求中使用了凭据,所以我们还需要将我们的应用程序的来源设置为我们的白名单,否则 cors 将“Access-Control-Allow-Origin”设置为“*”,这会导致浏览器内的安全错误.

            通过我的代理响应示例登录帖子请求:

                  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);
                  });
            

            【讨论】:

              猜你喜欢
              • 2014-08-30
              • 1970-01-01
              • 2016-12-09
              • 2018-10-21
              • 2019-12-29
              • 2020-09-15
              • 1970-01-01
              • 2019-03-17
              相关资源
              最近更新 更多