AngularJS $resource 为 $save 方法发出 HTTP OPTIONS 请求而不是 HTTP POST [英] AngularJS $resource makes HTTP OPTIONS request instead of HTTP POST for $save method

查看:28
本文介绍了AngularJS $resource 为 $save 方法发出 HTTP OPTIONS 请求而不是 HTTP POST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个简单的库应用程序,以便为使用 AngularJS 的更大项目做好准备.在网上阅读了很多关于使用 $resource 与 RESTful API 交互之后,我决定它可能会提供一些节省时间和扩展的好处来实现它而不是使用 $http 为每个请求.问题是,在使用 $save 方法时,我的 Node.js 控制台显示:

OPTIONS/books 200 1ms - 161b

使用 query() 方法工作正常 - Node 控制台显示:

GET/books 200 1ms - 228b

此时我已经被困了几个小时,尝试了下面的变体,但它总是最终成为 的 OPTIONS 请求而不是 POST(根据 Angular 文档应该是这样)$save 方法.

AngularJS 网络应用

app.js

var libraryApp = angular.module('libraryApp', ['ngResource', 'ngRoute', 'libraryControllers']);libraryApp.factory('$book', ['$resource', function ($resource) {返回 $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 = 函数 () {var b = 新 $book;b.isbn = "测试";b.description = "测试";b.价格= 9.99;b.$save();};}]);

Node.js 与 Express REST API

app.js

var express = require('express'),book = require('./routes/books'),http = require('http'),path = require('path');var app = express();...//启用跨域脚本app.all('*', function(req, res, next) {res.header("Access-Control-Allow-Origin", req.headers.origin);res.header("Access-Control-Allow-Headers", "X-Requested-With");下一个();});//路由app.get('/books', books.getAll);app.get('/books/:isbn', books.get);//这就是我想用 $save 方法触发的app.post('/books', books.add);http.createServer(app).listen(app.get('port'), function(){console.log('Express 服务器监听端口' + app.get('port'));});

./routes/books.js

<预><代码>...export.add = 函数(请求,资源){console.log("收到POST请求...");控制台日志(req.body.isbn);};

尝试将此行放在我的配置函数中 delete $httpProvider.defaults.headers.common["X-Requested-With"]; 但没有变化.

我不是 Angular/Node 专家,但现在我认为这与跨域有关,而且正如我所说,我不是 CORS 方面的专家.

提前致谢.

解决方案

我知道回答我自己的问题可能不合时宜,但我在发布这个问题几天后发现了这个问题.

这完全取决于浏览器如何管理 CORS.当在 JavaScript 中发出不简单"的跨域请求(即 GET 请求 - 这解释了 query() 函数工作的原因)时,浏览器将自动向指定的 URL/URI,称为飞行前"请求或承诺".只要远程源返回 HTTP 状态代码 200 以及有关它将在响应标头中接受的内容的相关详细信息,浏览器就会继续执行原始 JavaScript 调用.

这是一个简短的 jQuery 示例:

function makeRequest() {//浏览器向 www.myotherwebsite.com/api/test 发出 HTTP OPTIONS 请求//如果它收到 200 的 HTTP 状态代码和有关的相关详细信息//它会在 HTTP 标头中接受什么,然后它会发出这个 POST 请求...$.post( "www.myotherwebsite.com/api/test", function(data) {警报(数据);});//...如果不是那么它不会 - 就这么简单.}

我所要做的就是在响应标头中添加服务器将接受的内容的详细信息:

//将此规则应用于访问任何 URL/URI 的所有请求app.all('*', function(req, res, next) {//将 HTTP 请求标头中允许的内容的详细信息添加到响应标头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');//next() 函数继续执行并将移动到请求的 URL/URI下一个();});

然后在 Express 路由之前插入这几行,以便为每个 OPTIONS 请求简单地返回一个 HTTP 200 状态代码:

//完成飞行前/承诺请求app.options('*', function(req, res) {res.send(200);});

希望这能帮助任何在此页面上遇到同样问题的人.

I'm in the process of writing a simple library application to get ready for a larger project with AngularJS. After reading a lot online about using $resource to interact with a RESTful API, I decided that it would probably offer some time-saving and scaling benefits to implement it instead of using $http for each request. The problem is that for some reason (I'm no expert on CORS and the request is being sent cross-domain) when using the $save method my Node.js console shows:

OPTIONS /books 200 1ms - 161b 

Using the query() method works fine - the Node console shows:

GET /books 200 1ms - 228b

I've been stuck for several hours at this point, trying variations on the below but it always ends up being an OPTIONS request instead of POST (which is what it should be according to the Angular documentation) for the $save method.

AngularJS Web App

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

Node.js with Express REST API

app.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'));
});

./routes/books.js

...

exports.add = function(req, res) {

    console.log("POST request received...");
    console.log(req.body.isbn);
};

Tried putting this line in my config function delete $httpProvider.defaults.headers.common["X-Requested-With"]; but no change.

I'm no Angular/Node pro but right now I'm thinking that it's something to do with it being cross domain and, like I said, I'm no expert on CORS.

Thanks in advance.

解决方案

I know it may be in bad taste to answer my own question but I figured out the problem a few days after posting this.

It all comes down to how browsers manage CORS. When making a cross-domain request in JavaScript that is not "simple" (i.e. a GET request - which explains why the query() function worked), the browser will automatically make a HTTP OPTIONS request to the specified URL/URI, called a "pre-flight" request or "promise". As long as the remote source returns a HTTP status code of 200 and relevant details about what it will accept in the response headers, then the browser will go ahead with the original JavaScript call.

Here's a brief jQuery example:

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.
}

All I had to do was add the details of what the server will accept in the response headers:

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

And then insert these few lines before the Express routing to simply return a HTTP 200 status code for every OPTIONS request:

// fulfils pre-flight/promise request
app.options('*', function(req, res) {
    res.send(200);
});

Hopefully this will help anyone who stumbles on this page suffering from the same problem.

这篇关于AngularJS $resource 为 $save 方法发出 HTTP OPTIONS 请求而不是 HTTP POST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆