【发布时间】: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 请求
标签: angularjs node.js express cors angularjs-http