我试图在使用Express.js web框架的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)没有发送最初的选项请求。当我刚刚更新了块的资源,我需要提交一个跨起源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块设置标题?
使用Express Middleware非常适合我。如果您已经在使用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);
});
参考
我在我的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..