我正在尝试在使用 Express.js Web 框架的 Node.js 应用程序中支持 CORS。我已经阅读了有关如何处理此问题的 Google 小组讨论,并阅读了一些有关 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 块中设置标题?
我发现最简单的方法是使用 node.js 包cors 。最简单的用法是:
var cors = require('cors')
var app = express()
app.use(cors())
当然,有很多方法可以根据您的需要配置行为。上面链接的页面显示了许多示例。
尝试将控制权传递给下一条匹配的路线。如果 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 调用)的内容类型是除以下内容之外的任何内容类型:
application/x-www-form-urlencoded
multipart/form-data
text/plain
除上面列出的内容类型外,任何其他内容类型都将触发飞行前请求。
至于标头,除以下内容外,任何请求标头都将触发飞行前请求:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Save-Data
Viewport-Width
Width
其他任何请求标头都将触发飞行前请求。
因此,您可以添加一个自定义标头,例如: x-Trigger: CORS
,它应该触发飞行前请求并点击 OPTIONS 块。