AngularJS $资源使得HTTP OPTIONS请求而不是HTTP POST为$保存方法 [英] AngularJS $resource makes HTTP OPTIONS request instead of HTTP POST for $save method

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

问题描述

我在写一个简单的库应用程序来准备与​​AngularJS一个大项目的过程。在网上读了很多关于使用 $资源与一个RESTful API进行互动后,我决定,这可能会提供一些​​节省时间和缩放利益来实现它,而不是使用 $ HTTP 为每个请求。现在的问题是,由于某种原因(我对CORS没有专家和请求发送跨域)使用 $保存方法我Node.js的控制台显示了当

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

我一直停留几个小时在这一点,在下面试图变化,但它总是最终被一个OPTIONS请求,而不是在POST(这是它应根据角文档是什么)的 $保存方法。

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

与前preSS REST API

Node.js加载

app.js

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

./路线/ books.js

...

exports.add = function(req, res) {

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

试图把此行中我的​​配置功能删除$ httpProvider.defaults.headers.common [X-要求,以]; ,但没有改变。

我不是角/节点亲,但现在我认为它的东西,用它做是跨域,就像我说的,我对CORS没有专家。

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.

先谢谢了。

推荐答案

我知道这可能是不好的味道回答我的问题,但我张贴这几天后想通了这个问题。

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.

这一切都归结到浏览器如何管理CORS。当使得JavaScript的跨域请求不简单(即GET请求 - 这也解释了为什么查询()函数的工作),浏览器会自动进行一个HTTP OPTIONS请求到指定的URL / URI,称为pre-飞行请求或承诺。只要远程数据源返回200 HTTP状态code和相关细节什么它会在响应头接受,那么浏览器就会继续与原来的JavaScript调用。

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.

下面是一个简短的jQuery的例子:

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

,然后将前preSS路由之前的这几行简单地返回一个HTTP 200状态code,每OPTIONS请求:

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 $资源使得HTTP OPTIONS请求而不是HTTP POST为$保存方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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