没有“访问控制允许来源”-节点/ Apache端口问题


260

我使用Node / Express创建了一个小型API,并尝试使用Angularjs提取数据,但是由于我的html页面在localhost:8888上的apache下运行,并且node API在端口3000上进行侦听,我得到了否'Access-Control-允许来源”。我尝试使用 node-http-proxy和Vhosts Apache,但没有成功,请在下面查看完整的错误和代码。

XMLHttpRequest无法加载localhost:3000。所请求的资源上没有“ Access-Control-Allow-Origin”标头。因此,不允许访问源'localhost:8888'。”

// Api Using Node/Express    
var express = require('express');
var app = express();
var contractors = [
    {   
     "id": "1", 
        "name": "Joe Blogg",
        "Weeks": 3,
        "Photo": "1.png"
    }
];

app.use(express.bodyParser());

app.get('/', function(req, res) {
  res.json(contractors);
});
app.listen(process.env.PORT || 3000);
console.log('Server is running on Port 3000')

角度代码

angular.module('contractorsApp', [])
.controller('ContractorsCtrl', function($scope, $http,$routeParams) {

   $http.get('localhost:3000').then(function(response) {
       var data = response.data;
       $scope.contractors = data;
   })

的HTML

<body ng-app="contractorsApp">
    <div ng-controller="ContractorsCtrl"> 
        <ul>
            <li ng-repeat="person in contractors">{{person.name}}</li>
        </ul>
    </div>
</body>

Answers:


621

尝试将以下中间件添加到您的NodeJS / Express应用程序(为方便起见,我添加了一些注释):

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});

希望有帮助!


2
您能帮忙指定具体的去向吗?我的服务器中有以下代码。在这之后会继续吗?var app = require('express')(),server = require('http')。createServer(app),io = require('socket.io')。listen(server),request = require(“ request”) ,url = require(“ url”); server.listen(6969); //它在这里吗?在新的一行?
Art Geigel

1
@jvandemo我是否必须将app.get('/',function(req,res)更改为... function(req,res,next)?
Sangram Singh 2013年

10
你现在是我最喜欢的人。谢谢。我们是否可以添加一条注释,说明在为像我这样的菜鸟定义路由之前必须发生此代码?
gegillam '16

1
使用请求模块时如何使其工作?
罗希特·蒂加

2
就我而言,它不起作用。仍然出现此错误:“对预检请求的响应未通过访问控制检查:所请求的资源上没有'Access-Control-Allow-Origin'标头。因此,不允许源' abc.xyz.net:212 '访问。响应的HTTP状态码为500。”
user1451111

96

接受的答案很好,以防万一,您可以使用Express.js可用的名为cors的插件

对于这种特殊情况,使用起来很简单:

var cors = require('cors');

// use it before all route definitions
app.use(cors({origin: 'http://localhost:8888'}));

3
我必须使用{origin: 'null'}它才能工作...显然,我的浏览器将其null作为源发送?
里卡多·克鲁兹

2
为什么要重新发明轮子。与代码段相比,我始终希望获得打包的解决方案
Pierre

一个可爱的小库,很好地处理了我的用例,该用例想要来自不同来源的不同方法...并减少了下一个查看它的代码的疲劳。
凯尔·贝克

6
谢谢,app.use(cors({origin: '*'}));根据enable-cors为我工作。
danialk

2
我建议看看npm cors页面,以更好地利用它。这对我来说很清楚=)。
13013SwagR

30

另一种方法是,只需将标题添加到您的路由中:

router.get('/', function(req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // If needed
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); // If needed
    res.setHeader('Access-Control-Allow-Credentials', true); // If needed

    res.send('cors problem fixed:)');
});

8
)的笑脸使我感到困惑
diEcho

17

顶端回答工作对我很好,但我需要白名单不止一个域。

另外,最主要的答案是这样的事实,即OPTIONS请求不是由中间件处理的,并且您不会自动获得它。

allowed_origins在Express配置中存储了列入白名单的域,并根据origin标头放置了正确的域,因为Access-Control-Allow-Origin不允许指定多个域。

我最终得到的是:

var _ = require('underscore');

function allowCrossDomain(req, res, next) {
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');

  var origin = req.headers.origin;
  if (_.contains(app.get('allowed_origins'), origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }

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

app.configure(function () {
  app.use(express.logger());
  app.use(express.bodyParser());
  app.use(allowCrossDomain);
});

这是相同的'if(app.get('allowed origins')。indexOf(origin)!==-1)吗?'?
符文耶普森

13

答案代码仅允许localhost:8888。此代码无法部署到生产环境,也不能部署到其他服务器和端口名称。

为了使它适用于所有来源,请改用以下方法:

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', '*');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});

2
这对我不起作用!“ *不是有效来源”。似乎*字符未被识别为通配符。
Francesco'Sep

这个对我有用。即使用通配符“ *”。适用于Chrome和Safari。
AnBisw

谢谢;)运作良好
Mauro

9

在您的项目中安装cors依赖项:

npm i --save cors

将以下内容添加到服务器配置文件中:

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

它适用于我的2.8.4 cors版本。


"cors": "^2.8.5", "express": "^4.16.3",与@monikaja建议的行一起正常工作。谢谢!
RamiroIsBack

这是为了使所有来源/域都可以访问应用程序,而这通常是您不希望做的。而是仅指定允许的域。
Lacho Tomov

7

这对我有用。

app.get('/', function (req, res) {

    res.header("Access-Control-Allow-Origin", "*");
    res.send('hello world')
})

您可以更改*以适合您的需求。希望这会有所帮助。


7

嗨,这发生在前端和后端在不同端口上运行时。由于缺少CORS标头,浏览器阻止了来自后端的响应。解决方案是在后端请求中添加CORS标头。最简单的方法是使用cors npm软件包。

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

这将在所有请求中启用CORS标头。有关更多信息,请参阅cors文档。

https://www.npmjs.com/package/cors


3
app.all('*', function(req, res,next) {
    /**
     * Response settings
     * @type {Object}
     */
    var responseSettings = {
        "AccessControlAllowOrigin": req.headers.origin,
        "AccessControlAllowHeaders": "Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name",
        "AccessControlAllowMethods": "POST, GET, PUT, DELETE, OPTIONS",
        "AccessControlAllowCredentials": true
    };

    /**
     * Headers
     */
    res.header("Access-Control-Allow-Credentials", responseSettings.AccessControlAllowCredentials);
    res.header("Access-Control-Allow-Origin",  responseSettings.AccessControlAllowOrigin);
    res.header("Access-Control-Allow-Headers", (req.headers['access-control-request-headers']) ? req.headers['access-control-request-headers'] : "x-requested-with");
    res.header("Access-Control-Allow-Methods", (req.headers['access-control-request-method']) ? req.headers['access-control-request-method'] : responseSettings.AccessControlAllowMethods);

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


});

2

在NODEJ Restful API的app.js中添加以下代码,以避免在angular 6或任何其他框架中出现“ Access-Control-Allow-Origin”错误

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

1

您可以使用“ $ http.jsonp”

要么

以下是用于本地测试的chrome的解决方法

您需要使用以下命令打开镶边。(按窗口+ R)

Chrome.exe --allow-file-access-from-files

注意:您的镶边不能打开。运行此命令时,Chrome会自动打开。

如果要在命令提示符下输入此命令,请选择chrome安装目录,然后使用此命令。

下面的脚本代码用于MAC中带有“ --allow-file-access-from-files”的开放式Chrome浏览器

set chromePath to POSIX path of "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" 
set switch to " --allow-file-access-from-files"
do shell script (quoted form of chromePath) & switch & " > /dev/null 2>&1 &"

第二种选择

您可以只使用open(1)添加标志:open -a'Google Chrome'--args --allow-file-access-from-files


在MAC上呢?Chrome.exe --allow-file-access-from-files
user1336103 2013年

/ Applications / Google \ Chrome.app/Contents/MacOS/Google \ Chrome --allow-file-access-from-files设法打开chrome,但消息仍显示“ XMLHttpRequest无法加载localhost:3000。原始localhost:8888是不允许Access-Control-Allow-Origin。”
user1336103 2013年

+1我可以使用“ open”确认Mac选项是否可以使用此功能。我的情况有些不同,因为我只是测试一个完全下载的网站,该网站访问一些本地JSON文件。
13年

0

/**
 * Allow cross origin to access our /public directory from any site.
 * Make sure this header option is defined before defining of static path to /public directory
 */
expressApp.use('/public',function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    // Request headers you wish to allow
    res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    // Set to true if you need the website to include cookies in the requests sent
    res.setHeader('Access-Control-Allow-Credentials', true);
    // Pass to next layer of middleware
    next();
});


/**
 * Server is about set up. Now track for css/js/images request from the 
 * browser directly. Send static resources from "./public" directory. 
 */
expressApp.use('/public', express.static(path.join(__dirname, 'public')));
If you want to set Access-Control-Allow-Origin to a specific static directory you can set the following.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.