AngularJS 应用程序的 CORS GET 中未发送 HTTP 标头
Posted
技术标签:
【中文标题】AngularJS 应用程序的 CORS GET 中未发送 HTTP 标头【英文标题】:HTTP headers are not being sent in CORS GET from AngularJS application 【发布时间】:2016-04-05 03:31:54 【问题描述】:我的问题是我的 AngularJS HTTP GET 请求没有发送 HTTP 标头。但是,对于 HTTP POST,我确实看到设置了标头。这些 HTTP 请求通过 CORS。
虽然有很多关于这个问题的 SO 帖子,但我已经尝试过,但没有一个有效。一种解决方案建议如果数据字段为空,则不发送 HTTP 标头,并且我尝试了添加空数据值的建议(顺便说一下,这对于 HTTP GET 请求并没有真正意义),但是仍然,HTTP 标头没有成功。
在旁注中,我可能会捍卫这个帖子/问题可能值得称其为“不重复”(来自其他 SO 帖子),因为它处理 HTTP GET(与 HTTP POST 相对)和 CORS(相对于到非CORS)。
这是我的技术栈。
NodeJS v4.2.2 Express v4.13.3 AngularJS v1.4.0为了启用 CORS,我按照此处的示例 http://enable-cors.org/server_expressjs.html。我的 NodeJS 服务器应用程序如下所示。
var express = require('express');
var bodyParser = require('body-parser');
var morgan = require('morgan');
var jwt = require('jsonwebtoken');
var port = process.env.PORT || 8080;
var router = express.Router();
var app = express();
app.set('secret', 'mySecret');
app.use(express.static('public'));
app.use(bodyParser.urlencoded( extended: true ));
app.use(bodyParser.json());
app.use(morgan('dev'));
app.use('/api', router);
router.use(function(req, res, next)
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, x-access-token');
res.header('Access-Control-Allow-Methods', 'POST, PUT, GET, OPTIONS, DELETE');
next();
);
router.post('/authenticate', function(req, res)
var username = req.body.username;
var pw = req.body.password;
if(username !== 'root')
res.json(
success: false,
message: 'User not found'
);
else if(pw !== 'root')
res.json(
success: false,
message: 'Password wrong'
);
else
var user =
username: username,
pw: pw
;
var token = jwt.sign(user, app.get('secret'),
expiresIn: 60 * 60 * 24 * 365
);
res.json(
success: true,
message: 'Enjoy your token!',
token: token
);
);
router.use(function(req, res, next)
/* according to comments, have to ignore OPTIONS request from protection */
if('OPTIONS' === req.method) next(); return; //original post modified here to show, after adding this line, the OPTIONS is accessible, then the GET does actually send the required HTTP header
if('/api/authenticate' === req.originalUrl)
next();
return;
var token = req.body.token || req.params['token'] || req.headers['x-access-token'];
if(token)
jwt.verify(token, app.get('secret'), function(err, decoded)
if(err)
return res.json(
success: false,
message: 'Failed to authenticate token'
);
else
req.decoded = decoded;
next();
)
else
return res.status(403).send(
success: false,
message: 'No token provided'
);
);
router.get('/users', function(req, res)
res.json([
fname: 'john', lname: 'doe' ,
fname: 'jane', lname: 'smith'
]);
)
var server = app.listen(port, function()
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
);
我的 AngularJS 服务如下所示。
myServices.factory('HomeService', ['$resource', '$http', '$location', '$cookies', 'conf', function($resource, $http, $location, $cookies, conf)
var svc = ;
svc.getRestUrl = function()
return 'http://localhost:8080';
;
svc.sendData = function(url, data, method)
var restUrl = svc.getRestUrl() + url;
var options =
method: method,
url: restUrl,
withCredentials: false
;
var token = $cookies.get('token');
if(_.isEmpty(token))
options.headers =
'X-Requested-With': 'XMLHttpRequest'
;
else
options.headers =
'X-Requested-With': 'XMLHttpRequest',
'x-access-token': token
;
if(data)
options.data = data;
else
options.data = '';
return $http(options);
svc.getData = function(url)
return svc.sendData(url, null, 'GET');
;
svc.postData = function(url, data)
return svc.sendData(url, data, 'POST');
;
svc.authenticate = function(username, password)
var data = JSON.stringify(
username: username,
password: password
);
return svc.postData('/api/authenticate', data);
;
svc.getUsers = function()
return svc.getData('/api/users');
;
return svc;
]);
注意
对于服务的authenticate
方法,这是一个HTTP POST
对于服务的getUsers
,这是一个HTTP GET
当没有数据发送(HTTP GET)时,数据设置为空data: ''
使用 Fiddler,对于 authenticate
,我看到以下 HTTP 请求。
对于getUsers
,我看到以下 HTTP 请求。
关于 HTTP GET over CORS,我是否遗漏了一些未发送 HTTP 标头的内容?
【问题讨论】:
哪一个首先出现在您的代码中? GET 请求还是 POST 请求?如果您注意到,在 GET 的情况下,一个 OPTIONS 请求被触发,这是一个预检请求,当您在请求中发送自定义标头时发生。 POST 应该首先发生在authenticate
以获取 JSON Web 令牌 (JWT),然后是 GET 到 getUsers
(使用 JWT)。
OPTIONS 的响应似乎不错,列出了允许的来源、标头和方法。这是我所期望的。
这似乎与我的中间件和选项有关。当发出 OPTIONS 请求时,我得到一个 403(在 Fiddler 中看不到,但在 Chrome 控制台中显示)。看来我应该将 OPTIONS 请求排除为受保护的资源。关于如何做到这一点的任何想法?
由于您只在 nodejs 服务器中处理 post 和 get 请求,因此 OPTIONS 请求将发送到您正在检查令牌的默认处理程序,如果令牌不可用,您将提交 @987654331 @回复res.status(403).send()
。我认为您应该在此处更改代码以处理 OPTIONS 请求
【参考方案1】:
根据您的 HTTP 请求,在您的 getUsers
方法中向您的 CORS API 发出一个 OPTIONS 请求。
说到CORS,有2种请求
-
简单请求
预检请求
简单请求
一个简单的跨站请求是满足以下所有条件的:
唯一允许的方法是:
获取 头 发布除了由用户代理自动设置的标头外,唯一允许手动设置的标头是:
接受 接受语言 内容-语言 内容类型Content-Type 标头的唯一允许值是:
application/x-www-form-urlencoded 多部分/表单数据 文本/纯文本预检请求
如果您发出任何违反简单请求条件的请求,则会发送“预检”OPTIONS 请求以确定实际请求是否可以安全发送。特别是,如果满足以下条件,则预检请求:
它使用 GET、HEAD 或 POST 以外的方法。此外,如果使用 POST 发送 Content-Type 以外的请求数据 application/x-www-form-urlencoded, multipart/form-data, 或 文本/纯文本,例如如果 POST 请求向 服务器使用 application/xml 或 text/xml,那么请求是 预检。 它在请求中设置自定义标头(例如,请求使用标头 例如 X-PINGOTHER)有关 Preflighted Requests 的更多详细信息,您可以参考此 MDN link。
我相信这就是您的情况。即使您正在发出一个简单的 GET 请求,您也会添加 2 个自定义标头 X-Requested-With
和 x-access-token
,这使得验证 API 的安全性成为必要,因此浏览器会发送预检 OPTIONS 请求。只有在收到有效响应时,浏览器才会继续处理您的 GET 请求。
在您的 NodeJS 服务器代码中,您只处理对 /authenticate
的 POST 请求和对 /users
的 GET 请求,因此在 OPTIONS 请求的情况下,它将转到您正在检查令牌和的默认处理程序如果它不可用,您回复403
。所以我建议你改变你的代码来处理OPTIONS
请求。
【讨论】:
以上是关于AngularJS 应用程序的 CORS GET 中未发送 HTTP 标头的主要内容,如果未能解决你的问题,请参考以下文章