我正在编写一个简单的库应用程序,以准备使用AngularJS进行更大的项目。在在线阅读了很多有关$resource与RESTful API交互的知识之后,我决定实现它可能会带来一些节省时间和扩展性的好处,而不是$http用于每个请求。问题是由于某种原因(我不是CORS专家,并且请求正在跨域发送)在使用$save我的Node.js控制台显示的方法时:
$resource
$http
$save
OPTIONS /books 200 1ms - 161b
使用该query()方法效果很好-节点控制台显示:
query()
GET /books 200 1ms - 228b
在这一点上,我已经停留了几个小时,尝试对以下内容进行变体,但是对于该方法,它最终始终是OPTIONS请求而不是POST(根据Angular文档,应该是POST)$save。
app.js
var libraryApp = angular.module('libraryApp', ['ngResource', 'ngRoute', 'libraryControllers']); libraryApp.factory('$book', ['$resource', function ($resource) { return $resource('http://mywebserver\\:1337/books/:bookId', { bookId: '@bookId' }); }]);
controllers.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(); }; }]);
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')); });
./routes/books.js
... exports.add = function(req, res) { console.log("POST request received..."); console.log(req.body.isbn); };
试图把这行放在我的配置函数中,delete $httpProvider.defaults.headers.common["X-Requested- With"];但是没有变化。
delete $httpProvider.defaults.headers.common["X-Requested- With"];
我不是Angular / Node专业人士,但现在我在想这与跨域有关,就像我说的那样,我不是CORS专家。
提前致谢。
我知道回答自己的问题可能有点不好,但是在发布此问题几天后我就发现了问题。
一切都取决于浏览器如何管理CORS。当使用非“简单”的JavaScript发出跨域请求(即GET请求- 解释该query()功能为何起作用)时,浏览器将自动向指定的URL / URI发出HTTP OPTIONS请求,称为“ pre- 航班”请求或“承诺”。只要远程源返回200状态的HTTP状态代码以及响应标头中将接受的内容的相关详细信息,浏览器就会继续执行原始的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); });
希望这可以帮助在此页面上偶然遇到相同问题的任何人。