为什么在OPTIONS路由中添加CORS标头不允许浏览器访问我的API?

我正在尝试在使用Express.jsWeb框架的Node.js应用程序中支持CORS。我已经阅读了谷歌小组讨论关于如何处理这个问题,并阅读了一些关于CORS如何工作的文章。首先,我这样做了(代码是用CoffeeScript语法编写的):

app.options "*", (req, res) ->
res.header 'Access-Control-Allow-Origin', '*'
res.header 'Access-Control-Allow-Credentials', true
# try: 'POST, GET, PUT, DELETE, OPTIONS'
res.header 'Access-Control-Allow-Methods', 'GET, OPTIONS'
# try: 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept'
res.header 'Access-Control-Allow-Headers', 'Content-Type'
# ...

它似乎不起作用。似乎我的浏览器(Chrome)没有发送初始OPTIONS请求。当我刚刚更新资源块时,我需要提交一个跨源GET请求:

app.get "/somethingelse", (req, res) ->
# ...
res.header 'Access-Control-Allow-Origin', '*'
res.header 'Access-Control-Allow-Credentials', true
res.header 'Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS'
res.header 'Access-Control-Allow-Headers', 'Content-Type'
# ...

它(在Chrome)起作用。这在Safari也起作用。

我读过那…

在实现CORS的浏览器中,每个跨源GET或POST请求之前都有一个OPTIONS请求,用于检查GET或POST是否正常。

所以我的主要问题是,为什么在我的情况下似乎没有发生这种情况?为什么我的app.options块没有被调用?为什么我需要在我的主app.get块中设置标头?

820684 次浏览

尝试将控制传递到下一个匹配的路由。如果Express首先匹配app.get路由,则它不会继续到选项路由,除非您执行以下操作(注意使用next)

app.get('somethingelse', function(req, res, next) {
//..set headers etc.


next();
});

在组织CORS方面,我把它放在一个中间件中,这个中间件对我来说工作得很好:

//CORS middleware
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'example.com');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');


next();
}


//...
app.configure(function() {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'cool beans' }));
app.use(express.methodOverride());
app.use(allowCrossDomain);
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});

为了回答您的主要问题,如果POST或GET中包含任何非简单内容或标头,CORS规范只要求OPTIONS调用在POST或GET之前。

需要CORS飞行前请求(OPTIONS调用)的Content-Type是任何Content-Type除了以下

  1. application/x-www-form-urlencoded
  2. multipart/form-data
  3. text/plain

除上面列出的内容类型之外的任何其他内容类型都将触发飞行前请求。

对于标头,任何请求标头除了以下都将触发飞行前请求:

  1. Accept
  2. Accept-Language
  3. Content-Language
  4. Content-Type
  5. DPR
  6. Save-Data
  7. Viewport-Width
  8. Width

任何其他请求标头将触发飞行前请求。

因此,您可以添加一个自定义标头,例如:x-Trigger: CORS,这应该触发飞行前请求并命中OPTIONS块。

查看MDN Web API参考-CORS预置请求

为了保持相同的路由理念。我使用这段代码:

app.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});

类似于http://enable-cors.org/server_expressjs.html示例

我制作了一个更完整的中间件,适用于Express或Connect。它支持OPTIONS请求进行飞行前检查。请注意,它将允许CORS访问任何内容,如果您想限制访问,您可能需要进行一些检查。

app.use(function(req, res, next) {
var oneof = false;
if(req.headers.origin) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
oneof = true;
}
if(req.headers['access-control-request-method']) {
res.header('Access-Control-Allow-Methods', req.headers['access-control-request-method']);
oneof = true;
}
if(req.headers['access-control-request-headers']) {
res.header('Access-Control-Allow-Headers', req.headers['access-control-request-headers']);
oneof = true;
}
if(oneof) {
res.header('Access-Control-Max-Age', 60 * 60 * 24 * 365);
}


// intercept OPTIONS method
if (oneof && req.method == 'OPTIONS') {
res.send(200);
}
else {
next();
}
});

我发现最简单的方法是使用node.js包cors。最简单的用法是:

var cors = require('cors')


var app = express()
app.use(cors())

当然,有很多方法可以根据您的需求配置行为;上面链接的页面显示了许多示例。

我对Express 4.2.0最简单的解决方案(编辑:似乎在4.3.0中不起作用)是:

function supportCrossOriginScript(req, res, next) {
res.status(200);
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type");


// res.header("Access-Control-Allow-Headers", "Origin");
// res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// res.header("Access-Control-Allow-Methods","POST, OPTIONS");
// res.header("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE, PUT, HEAD");
// res.header("Access-Control-Max-Age","1728000");
next();
}


// Support CORS
app.options('/result', supportCrossOriginScript);


app.post('/result', supportCrossOriginScript, function(req, res) {
res.send('received');
// do stuff with req
});

我想做app.all('/result', ...)也会奏效…

使用Express+node+ionic在不同端口运行完成测试。

Localhost:8100

Localhost:5000

// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests


app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});

这对我来说很有效,因为它在路由中是一个简单的实现,我使用的是Meanjs及其工作精细、Safari、chrome等。

app.route('/footer-contact-form').post(emailer.sendFooterMail).options(function(req,res,next){
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
return res.send(200);


});

做这样的事情:

app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

我发现使用npm请求包(https://www.npmjs.com/package/request)非常容易做到这一点

然后我把我的解决方案基于这篇文章http://blog.javascripting.com/2015/01/17/dont-hassle-with-cors/

'use strict'


const express = require('express');
const request = require('request');


let proxyConfig = {
url : {
base: 'http://servertoreach.com?id=',
}
}


/* setting up and configuring node express server for the application */
let server = express();
server.set('port', 3000);




/* methods forwarded to the servertoreach proxy  */
server.use('/somethingElse', function(req, res)
{
let url = proxyConfig.url.base + req.query.id;
req.pipe(request(url)).pipe(res);
});




/* start the server */
server.listen(server.get('port'), function() {
console.log('express server with a proxy listening on port ' + server.get('port'));
});

我们可以避免CORS并将请求转发到其他服务器:

// config:
var public_folder = __dirname + '/public'
var apiServerHost = 'http://other.server'


// code:
console.log("starting server...");


var express = require('express');
var app = express();
var request = require('request');


// serve static files
app.use(express.static(public_folder));


// if not found, serve from another server
app.use(function(req, res) {
var url = apiServerHost + req.url;
req.pipe(request(url)).pipe(res);
});


app.listen(80, function(){
console.log("server ready");
});

安装Expresjs的cors模块。你可以按照这些步骤>

安装

npm install cors

简单使用(启用所有CORS请求)

var express = require('express');
var cors = require('cors');
var app = express();
app.use(cors());

有关更多详细信息,请访问https://github.com/expressjs/cors

npm install cors --save

只需将这些行添加到您的请求所在的主文件中(将其保留在任何路由之前)。

const cors = require('cors');
const express = require('express');
let app = express();
app.use(cors());
app.options('*', cors());

前段时间,我遇到了这个问题,所以我这样做是为了在我的nodejs应用程序中允许CORS:

首先使用以下命令需要安装cors

npm install cors --save

现在添加以下代码到您的应用程序起始文件,例如(app.js or server.js

var express = require('express');
var app = express();


var cors = require('cors');
var bodyParser = require('body-parser');


//enables cors
app.use(cors({
'allowedHeaders': ['sessionId', 'Content-Type'],
'exposedHeaders': ['sessionId'],
'origin': '*',
'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'preflightContinue': false
}));


require('./router/index')(app);

首先简单地在项目中安装cors。 将终端(命令提示符)和cd带到您的项目目录并运行以下命令:

npm install cors --save

然后获取server.js文件并更改代码以在其中添加以下内容:

var cors = require('cors');




var app = express();


app.use(cors());


app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

这对我工作…

如果您想使其特定于控制器,您可以使用:

res.setHeader("X-Frame-Options", "ALLOWALL");
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "POST, GET");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

请注意,这也将允许iFrame。

我对我的网络应用程序使用了以下步骤,我取得了成功:

将cors包裹添加到快递中:

npm install cors --save

添加以下行在身体分析器配置之后。我在身体分析器之前添加时遇到了一些麻烦:

 // enable cors to the server
const corsOpt = {
origin: process.env.CORS_ALLOW_ORIGIN || '*', // this work well to configure origin url in the server
methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'], // to works well with web app, OPTIONS is required
allowedHeaders: ['Content-Type', 'Authorization'] // allow json and token in the headers
};
app.use(cors(corsOpt)); // cors for all the routes of the application
app.options('*', cors(corsOpt)); // automatic cors gen for HTTP verbs in all routes, This can be redundant but I kept to be sure that will always work.

在打字稿中,如果要使用node.js包cors

/**
* app.ts
* If you use the cors library
*/


import * as express from "express";
[...]
import * as cors from 'cors';


class App {
public express: express.Application;


constructor() {
this.express = express();
[..]
this.handleCORSErrors();
}


private handleCORSErrors(): any {
const corsOptions: cors.CorsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200
};
this.express.use(cors(corsOptions));
}
}


export default new App().express;

如果您不想使用第三部分库进行cors错误处理,则需要更改handleCORSEr的()方法。

/**
* app.ts
* If you do not use the cors library
*/


import * as express from "express";
[...]


class App {
public express: express.Application;


constructor() {
this.express = express();
[..]
this.handleCORSErrors();
}


private handleCORSErrors(): any {
this.express.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-ALlow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
if (req.method === "OPTIONS") {
res.header(
"Access-Control-Allow-Methods",
"PUT, POST, PATCH, GET, DELETE"
);
return res.status(200).json({});
}
next(); // send the request to the next middleware
});
}
}


export default new App().express;

使用app.ts文件

/**
* server.ts
*/
import * as http from "http";
import app from "./app";


const server: http.Server = http.createServer(app);


const PORT: any = process.env.PORT || 3000;
server.listen(PORT);

使用Express中间件对我来说很棒。如果您已经在使用Express,只需添加以下中间件规则。它应该开始工作了。

app.all("/api/*", function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
res.header("Access-Control-Allow-Methods", "GET, PUT, POST");
return next();
});


app.all("/api/*", function(req, res, next) {
if (req.method.toLowerCase() !== "options") {
return next();
}
return res.send(204);
});

参考

可以参考下面的代码进行相同的操作。来源:一个cade Mind/node-restful-api

const express = require('express');
const app = express();


//acts as a middleware
//to handle CORS Errors
app.use((req, res, next) => { //doesn't send response just adjusts it
res.header("Access-Control-Allow-Origin", "*") //* to give access to any origin
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization" //to give access to all the headers provided
);
if(req.method === 'OPTIONS'){
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET'); //to give access to all the methods provided
return res.status(200).json({});
}
next(); //so that other routes can take over
})

下面的代码将工作,但首先安装cors:

npm install--保存cors

然后:

module.exports = function(app) {
var express = require("express");
var cors = require('cors');
var router = express.Router();
app.use(cors());


app.post("/movies",cors(), function(req, res) {
res.send("test");
});

这与帕特的回答相似,区别在于我用res.send状态(200)结束;而不是下一个();

代码将捕获方法类型OPTIONS的所有请求并发回访问控制标头。

app.options('/*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
res.sendStatus(200);
});

该代码按照问题中的要求接受来自所有来源的CORS。但是,最好将*替换为特定来源,即http://localhost:8080以防止误用。

由于我们使用app.options方法而不是app.use方法,我们不需要进行此检查:

req.method === 'OPTIONS'

我们可以从其他一些答案中看到。

我在这里找到了答案:http://johnzhang.io/options-request-in-express

使用nodejs没有Express/外部库我在我的server.js文件中使用了下面的方法。这里的关键部分是从请求标头中获取源,然后在服务器响应中允许它,此时我们可以设置将返回的标头,包括如果找到匹配的允许的源。

    **const origin = req.headers.origin;**


let decoder = new StringDecoder('utf-8');
let buffer = '';
req.on('data', function (data) {
buffer += decoder.write(data);
});
req.on('end', function () {
buffer += decoder.end();


let chosenHandler = typeof (server.router[trimmedPath]) !== 'undefined' ? server.router[trimmedPath] : handlers.notFound;


const data = { ....data object vars}


// should be wrapped in try catch block
chosenHandler(data, function (statusCode, payload, contentType) {
server.processHandlerResponse(res, method, trimmedPath, statusCode, payload, contentType, **origin**);




server.processHandlerResponse = function (res, method, trimmedPath, statusCode, payload, contentType, origin) {
contentType = typeof (contentType) == 'string' ? contentType : 'json';


statusCode = typeof (statusCode) == 'number' ? statusCode : 200;


let payloadString = '';
if (contentType == 'json') {
res.setHeader('Content-Type', 'application/json');


const allowedOrigins = ['https://www.domain1.com', 'https://someotherdomain','https://yetanotherdomain',
...// as many as you need
];
**if (allowedOrigins.indexOf(origin) > -1) {
res.setHeader('Access-Control-Allow-Origin', origin);
}**
payload = typeof (payload) == 'object' ? payload : {};
payloadString = JSON.stringify(payload);
}


... //  if (other content type) ...rinse and repeat..

下面的工作对我来说,希望它能帮助别人!

const express = require('express');
const cors = require('cors');
let app = express();


app.use(cors({ origin: true }));

引用自https://expressjs.com/en/resources/middleware/cors.html#configuring-cors

最简单的方法是使用以下方法在项目中安装cors模块:

npm i --save cors

然后在您的服务器文件中使用以下命令导入它:

import cors from 'cors';

然后简单地将其用作中间件,如下所示:

app.use(cors());

希望这有帮助!

在我的index.js中,我添加了:

app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
next();
})

如果我是你@OP,我会改变我的编程范式。

假设您正在阻止这些CORS,因为您正在向localhost或类似的东西发出请求。

最终,如果您要部署到生产optoins,如Google Cloud PlatformHeroku或,您将不必担心CORS,如允许起源或任何在生产时。

因此,在测试服务器时,只需使用postman,您就不会遇到CORS阻塞,之后部署您的服务器,然后在您的客户端上工作。

您可以使用Express中间件,阻止您的域和方法。

app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", process.env.DOMAIN); // update to match the domain you will make the request from
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});

最简单的答案是使用cors包

const cors = require('cors');


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

这将全面启用CORS。如果您想学习如何无需外部模块即可启用CORS,您真正需要的只是一些设置“访问控制允许源”标头Express中间件。这是允许从浏览器到服务器跨请求域所需的最低要求。

app.options('*', (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
res.send('ok');
});


app.use((req, res) => {
res.set('Access-Control-Allow-Origin', '*');
});

/*首先,这可能是初级开发人员的问题,比如我自己:确保在你的获取方法中使用"lambda" >>>> "`" 而不是"'"!*/

"'const响应=等待获取(https://api....);

/另外,强烈推荐下面的文章:https://developer.edamam.com/api/faq/

简单就是难:

 let my_data = []
const promise = new Promise(async function (resolve, reject) {
axios.post('https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/directions/json?origin=33.69057660000001,72.9782724&destination=33.691478,%2072.978594&key=AIzaSyApzbs5QDJOnEObdSBN_Cmln5ZWxx323vA'
, { 'Origin': 'https://localhost:3000' })
.then(function (response) {
console.log(`axios response ${response.data}`)
const my_data = response.data
resolve(my_data)
})
.catch(function (error) {
console.log(error)
alert('connection error')
})
})
promise.then(data => {
console.log(JSON.stringify(data))
})

在您的主js文件中尝试此操作:

app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Authorization, X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Allow-Request-Method"
);
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
res.header("Allow", "GET, POST, OPTIONS, PUT, DELETE");
next();
});

这应该能解决你的问题

使用CORS包。并将此参数:

cors({credentials: true, origin: true, exposedHeaders: '*'})

如果你想让CORS在没有cors NPM包的情况下工作(为了纯粹的学习乐趣!),你绝对可以自己处理选项调用。这是对我有效的方法:

app.options('*', (req, res) => {
res.writeHead(200, '', {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS',
}).end();
});

不错很简单,对吧?请注意使用res.write()而不是我不熟悉的res.header()。

建议使用cors包来解决express.js中的CORS策略问题,但您还需要确保为app.options启用它,如下所示:

const cors = require('cors');


// enable cors
app.use(
cors({
origin: true,
optionsSuccessStatus: 200,
credentials: true,
})
);
app.options(
'*',
cors({
origin: true,
optionsSuccessStatus: 200,
credentials: true,
})
);

如果您的Express Server有授权开启,您可以这样实现

const express = require('express');
const app=express();
const cors=require("cors");
app.use(cors({
credentials: true, // for authorization
}));
...