CORS 和 s-s-r 以及 express、react 和 Axios

Posted

技术标签:

【中文标题】CORS 和 s-s-r 以及 express、react 和 Axios【英文标题】:CORS with s-s-r with express, react and Axios 【发布时间】:2021-01-26 19:16:45 【问题描述】:

我正在开发一个 APP(由 express 提供的 React:s-s-r),它必须与公共 API 连接,并且我从 chrome 收到下一条消息:

从源“http://localhost:3000”访问“https://api.musixmatch.com/ws/1.1/track.search?q_track=There%20will%20be%20blood&apikey=value”的 XMLHttpRequest被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。

所以我在我的客户端中使用下一个配置/标题设置 axios

const instance = axios.create(
  baseURL: urlServer,
);

const options = 
  headers: 
    "Access-Control-Allow-Origin": "*",
    "Content-Type": "application/json",
  ,
  params: 
    apikey: "value",
  ,
;

export const getUsers = () =>
  instance.get(`track.search?q_track=There will be blood`, options);

我也试过把它放在 webpack 上:

devServer: 
    historyApiFallback: true,
    headers: 
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Headers":
        "Origin, X-Requested-With, Content-Type, Accept",
    ,
  ,

这是我的 server.js

import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import webpack from "webpack";
import helmet from "helmet";
import React from "react";
import  renderToString  from "react-dom/server";
import  renderRoutes  from "react-router-config";
import  StaticRouter  from "react-router-dom";
import  Layout  from "components";
import serverRoutes from "../frontend/routes/serverRoutes";
import getManifest from "./getManifest";

dotenv.config();

const  ENV, PORT_DEV, PORT_PRO  = process.env;
const port = ENV === "development" ? PORT_DEV : PORT_PRO;

const app = express();
app.use(cors());

if (ENV === "development") 
  console.log("#########################################");
  console.log("Enviroment: ", "Working on develop");

  const webpackConfig = require("../../webpack.config");
  const webpackDevMiddleware = require("webpack-dev-middleware");
  const webpackHotMiddleware = require("webpack-hot-middleware");
  const compiler = webpack(webpackConfig);

  const webpackServerConfig = 
    port: port,
    hot: true,
  ;

  app.use(webpackDevMiddleware(compiler, webpackServerConfig));
  app.use(webpackHotMiddleware(compiler));


if (ENV === "production") 
  app.use((request, response, next) => 
    if (!request.hashManifest) 
      request.hashManifest = getManifest();
    
    next();
  );
  app.use(express.static(`$__dirname/public`));
  app.use(helmet());
  app.use(helmet.permittedCrossDomainPolicies());
  app.disable("x-powered-by");


const setResponse = (html, manifest) => 
  const mainStyles = manifest ? manifest["main.css"] : "assets/main.css";
  const mainBuild = manifest ? manifest["main.js"] : "assets/main.js";
  const vendorBuild = manifest ? manifest["vendors.js"] : "assets/vendor.js";

  return `
      <!DOCTYPE html>
      <html lang="es">
        <head>
          <meta charset="utf-8" />
          <link href="$mainStyles" rel="stylesheet" type="text/css">
          <title>React App</title>
        </head>
        <body>
          <div id="root">$html</div>
          <script src="$mainBuild" type="text/javascript"></script>
          <script src="$vendorBuild" type="text/javascript"></script>
        </body>
      </html>
    `;
;

const renderApp = (request, response) => 
  const html = renderToString(
    <Layout>
      <StaticRouter location=request.url context=>
        renderRoutes(serverRoutes)
      </StaticRouter>
    </Layout>
  );

  response.send(setResponse(html, request.hashManifest));
;

app.get("*", renderApp);

app.listen(port, (error) => 
  if (error) 
    console.log("Error: ", "can not run the server.");
   else 
    console.log(`Server running on port $port - $ENV`);
    console.log("#########################################");
  
);

我尝试使用邮递员获取数据并且它有效。但如果我从我的 APP 尝试,它没有。

我需要在 express 文件 (server.js) 上设置请求吗? 我是否在客户的请求中遗漏了某些内容? 我可以在客户端做请求吗?

关于一般标题的更多信息。它给了我这对键值:

推荐人政策:strict-origin-when-cross-origin

【问题讨论】:

您不应该直接从客户端应用程序发出该请求,然后您必须与您的用户共享您的令牌。 CORS 是通过的,但请注意,您无法通过在客户端中添加标头来修复它(它们是需要由服务器设置的响应标头)。您应该编写某种后端(Express 或其他)来代理该请求,这样您就可以将令牌保密。 感谢您的推荐。我试试看 嗨,你试过安装cors吗? expressjs.com/en/resources/middleware/cors.html 是的,我正在使用 cors。也许可能是 CORS 和 Helmet 之间的问题或冲突? 【参考方案1】:

正如@lissettdm 建议的那样,我使用的是 cors 但没有正确的配置。

我仔细阅读了http://expressjs.com/en/resources/middleware/cors.html 的文档,发现我们可以设置我们信任的来源。

所以我做到了:

app.use(
  cors(
    origin: ["https://api.musixmatch.com"],
  )
);

这会将域添加到信任,它会让我们从客户端发出请求。就我而言,我不想隐藏 apikey,因为在同一个请求中我必须发送它,但正如 @jonrsharpe 建议的那样,我们不能显示该信息。

【讨论】:

以上是关于CORS 和 s-s-r 以及 express、react 和 Axios的主要内容,如果未能解决你的问题,请参考以下文章

React/Node/Express 和 google OAuth 的 CORS/CORB 问题

使用 express 和 webpack 构建 react s-s-r 服务器的问题

Express路由路径匹配规则以及第三方包模块cors

Node、Express、Oauth2 和 Passport 的 Angularjs CORS 问题

Vue.js 3 s-s-r - 客户端水合期间缺少模板或渲染功能

CORS 403 错误 Angular 和 Express