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


当前回答

为了回答您的主要问题,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预飞请求

其他回答

使用CORS包。然后输入这些参数:

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

在typescript中,如果你想使用node.js包cors .js

/**
* 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错误处理,则需要更改handleCORSErrors()方法。

/**
* 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);

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

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

很简单,对吧?注意使用res.writeHead()而不是res.header(),这一点我不熟悉。

最简单的答案是使用cors包。

const cors = require('cors');

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

这将使CORS全面启用。如果你想学习如何在没有外部模块的情况下启用CORS,你真正需要的只是一些Express中间件,它可以设置“Access-Control-Allow-Origin”标头。这是允许从浏览器到服务器的交叉请求域所需的最小值。

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

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

express + node +离子在不同端口运行时进行测试。

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();
});