我正在编写一个简单的库应用程序,以便为使用AngularJS的大型项目做好准备。在网上阅读了很多关于使用$resource
与RESTful API交互的内容之后,我认为它可能会提供一些节省时间和扩展的好处来实现它,而不是为每个请求使用$http
。问题是,由于某种原因(我不是CORS的专家,并且请求是跨域发送的),在使用$save
方法时,我的Node.js控制台显示:
OPTIONS /books 200 1ms - 161b
使用query()
方法可以正常工作 - 节点控制台显示:
GET /books 200 1ms - 228b
此时我已经被困了几个小时,尝试下面的变化,但它总是最终成为一个OPTIONS请求而不是POST(这是根据Angular文档应该是什么){{1方法。
app.js
$save
controllers.js
var libraryApp = angular.module('libraryApp', ['ngResource', 'ngRoute', 'libraryControllers']);
libraryApp.factory('$book', ['$resource', function ($resource) {
return $resource('http://mywebserver\\:1337/books/:bookId', { bookId: '@bookId' });
}]);
app.js
var libraryControllers = angular.module('libraryControllers', []);
libraryControllers.controller('BookCtrl', ['$scope', '$book', function($scope, $book) {
...
$scope.addBook = function () {
var b = new $book;
b.isbn = "TEST";
b.description = "TEST";
b.price = 9.99;
b.$save();
};
}]);
./路由/ books.js
var express = require('express'),
books = require('./routes/books'),
http = require('http'),
path = require('path');
var app = express();
...
// enable cross-domain scripting
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
// routing
app.get('/books', books.getAll);
app.get('/books/:isbn', books.get);
// This is what I want to fire with the $save method
app.post('/books', books.add);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
尝试将此行放入我的配置函数...
exports.add = function(req, res) {
console.log("POST request received...");
console.log(req.body.isbn);
};
但没有更改。
我不是Angular / Node pro,但现在我认为它与跨域有关,就像我说的那样,我不是CORS的专家。
提前致谢。
答案 0 :(得分:43)
我知道回答我自己的问题可能不太好,但是在发布这个问题几天后我就发现了这个问题。
这一切都归结为浏览器如何管理CORS。在JavaScript中创建一个非简单的跨域请求时#34; (即GET请求 - 解释query()
函数工作的原因),浏览器将自动向指定的URL / URI发出HTTP OPTIONS请求,称为"飞行前"请求或"承诺"。只要远程源返回HTTP状态代码200以及它将在响应头中接受的内容的相关详细信息,浏览器就会继续使用原始的JavaScript调用。
这是一个简短的jQuery示例:
function makeRequest() {
// browser makes HTTP OPTIONS request to www.myotherwebsite.com/api/test
// and if it receives a HTTP status code of 200 and relevant details about
// what it will accept in HTTP headers, then it will make this POST request...
$.post( "www.myotherwebsite.com/api/test", function(data) {
alert(data);
});
// ...if not then it won't - it's that simple.
}
我所要做的就是在响应标题中添加服务器接受的详细信息:
// apply this rule to all requests accessing any URL/URI
app.all('*', function(req, res, next) {
// add details of what is allowed in HTTP request headers to the response headers
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Credentials', false);
res.header('Access-Control-Max-Age', '86400');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
// the next() function continues execution and will move onto the requested URL/URI
next();
});
然后在Express路由之前插入这几行,只为每个OPTIONS请求返回一个HTTP 200状态代码:
// fulfils pre-flight/promise request
app.options('*', function(req, res) {
res.send(200);
});
希望这可以帮助任何偶然发现此页面的人遇到同样的问题。
答案 1 :(得分:1)
我实际上没有尝试过这个,但是不足以告诉Ressource如何处理$ save请求?
$resource('http://mywebserver\\:1337/books/:bookId', { bookId: '@bookId' }, {save: {method: 'POST'});