我试图在使用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块设置标题?


当前回答

保持相同的路由思想。我使用这个代码:

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的例子

其他回答

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

需要CORS飞行前请求(OPTIONS调用)的内容类型是任何内容类型,除了以下内容:

应用程序/ x-www-form-urlencoded 多部分/格式 文本/平原

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

对于header,除了以下以外的任何Request header都会触发一个pre-flight Request:

接受 接收语言 内容语言 内容类型 DPR 保存数据 Viewport-Width 宽度

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

因此,您可以添加一个自定义报头,如:x-Trigger: CORS,它应该触发飞行前请求并点击OPTIONS块。

参见MDN Web API参考- CORS预飞请求

在你的主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();
});

这应该能解决你的问题

我已经做了一个更完整的中间件,适合表达或连接。它支持飞行前检查的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())

当然,有很多方法来配置行为以满足您的需求;上面链接的页面显示了一些例子。

我发现用npm request包(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'));
});