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

Posted

技术标签:

【中文标题】React/Node/Express 和 google OAuth 的 CORS/CORB 问题【英文标题】:CORS/CORB issue with React/Node/Express and google OAuth 【发布时间】:2019-03-14 15:56:12 【问题描述】:

我有一个 React 应用程序,我正在尝试使用 OAuth 添加一个 Node/Express/mysql 后端。我的 React 应用程序托管在 localhost:3000 上,而 express 服务器位于 localhost:4000 上。我在 react 应用的 package.json 文件中添加了 "proxy":"http://localhost:4000" 以向服务器发送请求。 OAuth 的授权 javascript 来源是 http://localhost:4000。授权重定向 URI 是 http://localhost:4000/auth/google/redirect。

这些是我在尝试访问服务器上的路由时在浏览器控制台中遇到的错误:

有人说请求的资源上不存在“Access-Control-Allow-Origin”标头。

另一个说“跨域读取阻止 (CORB) 阻止了跨域响应......使用 MIME 类型文本/html。”

我不知道我做错了什么,从昨天开始我就被困住了。

Failed to load https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4000%2Fauth%2Fgoogle%2Fredirect&scope=profile&client_id=clientiddeletedbyme.apps.googleusercontent.com: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.   

Cross-Origin Read Blocking (CORB) blocked cross-origin response https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4000%2Fauth%2Fgoogle%2Fredirect&scope=profile&client_id=iddeletedbymeapps.googleusercontent.com with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.

这是我的 react 应用程序的 package.json 文件中的代码:


  "name": "workout_tracker",
  "version": "0.1.0",
  "private": true,
  "dependencies": 
    "axios": "^0.18.0",
    "firebase": "^5.3.0",
    "jw-paginate": "^1.0.2",
    "jw-react-pagination": "^1.0.7",
    "normalize.css": "^8.0.0",
    "random-id": "0.0.2",
    "react": "^16.5.2",
    "react-dom": "^16.5.2",
    "react-headroom": "^2.2.2",
    "react-icons-kit": "^1.1.6",
    "react-redux": "^5.0.7",
    "react-router-dom": "^4.3.1",
    "react-scripts-cssmodules": "^1.1.10",
    "react-swipe-to-delete-component": "^0.3.4",
    "react-swipeout": "^1.1.1",
    "redux": "^4.0.0",
    "redux-thunk": "^2.3.0"
  ,
  "scripts": 
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  ,
  "devDependencies": 
    "redux-devtools-extension": "^2.13.5"
  ,
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "proxy":"http://localhost:4000"

这是我的 react 应用程序中将请求发送到服务器的代码:

express=()=>
axiosInstance.get("/google").then(res=>
  console.log(res);
).catch(err=>console.log(err));

这是服务器中的代码

   let express = require("express");
let cors= require("cors");
let mysql = require("mysql");
const util = require("util");
const passportSetup = require("./config/passport-setup");
const passport = require("passport");

let app = express();

let connection =mysql.createConnection(
    host: "localhost",
    user: "root",
    password: "root",
    database: "Workout_Tracker",
    socketPath: '/Applications/MAMP/tmp/mysql/mysql.sock'
);



app.use(cors(
origin:"http://localhost:3000",
    credentials:true,
    allowHeaders:"Content-Type"

));

app.options("/google", cors());
app.get("/google", cors(), passport.authenticate("google",

    scope:['profile']

));

...omitted a bunch of SQL queries

app.listen(4000, () => console.log("Listening on port 4000!"));

【问题讨论】:

【参考方案1】:

这是您需要安装的新中间件的示例代码,以表达定义任何路由之前:

const cors = require('cors');

app.use('*', function(req, res, next) 
//replace localhost:8080 to the ip address:port of your server
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Credentials', true);
next(); 
);

//enable pre-flight
app.options('*', cors());

但在复制和粘贴之前,您需要知道在导入 cors 之前需要 npm install cors --save。上面的示例代码简单的意思是:

    我们允许不同的 IP 地址访问您定义的所有路由的服务器 在标头中允许使用“X-Requested-With”和“Content-Type”参数。您通常不必专门定义这些,但拥有它们很好。 只有将允许凭据设置为 true,您的会话/cookie 才能在前端刷新页面期间存储,我认为这可能对您未来的开发有所帮助。 飞行前请求也将被允许,许多Http库默认发送。 对于你的前端,如果你使用的是 axios,你确实需要:axios.create( withCredentials: true ); 说:react 和 express 都同意使用 CORS。同样在其他 http 库中。

您可以查看以下文档: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

【讨论】:

【参考方案2】:

我应该通过浏览器导航到那里,而不是使用 AJAX 来请求端点。我使用了 &lt;a&gt; 标签和 href 的“http://localhost:4000”,它按预期工作。

【讨论】:

【参考方案3】:

这是我在 expressJs 中使用 CORS 的示例,这需要在后端或服务器端完成。服务器停止从外部世界而不是客户端访问它的 API。

// IP's allowed all access this server
let whitelist = ['http://localhost:3000', 'http://127.0.0.1:3000'];

let corsOptions = 
  origin: function (origin, callback) 
    if (whitelist.indexOf(origin) !== -1) 
      callback(null, true);
     else 
      callback(new Error('Not allowed by CORS'));
    
  
;

// Cross-Origin Resource Sharing
app.use(cors(corsOptions));

【讨论】:

以上是关于React/Node/Express 和 google OAuth 的 CORS/CORB 问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 Amazon AWS 将 React、Node/Express 和 MySQL Web 应用程序部署到 Web 上

如何在 Cookie 上指定 SameSite 和 Secure(使用 axios/React/Node Express)

React + Node Express,下载的docx文件已损坏

React 路由与 Express 路由

Springboot框架了解与搭建

谷歌钱包应用内付款:未捕获的 ReferenceError:未定义 goog。 google.payments 与 goog.payments