web-dev-qa-db-ja.com

AngularJS $ resourceは、HTTPの代わりにHTTP OPTIONSリクエストを作成しますPOST for $ save method

私は、AngularJSを使用してより大きなプロジェクトの準備をするための単純なライブラリアプリケーションを作成している最中です。 _$resource_を使用してRESTful APIとやり取りすることについてオンラインでたくさん読んだ後、私は、リクエストごとに_$http_を使用する代わりに、おそらく時間の節約とスケーリングの利点を提供することに決めました。問題は、何らかの理由で(私はCORSの専門家ではなく、リクエストがクロスドメインで送信されているため)_$save_メソッドを使用すると、Node.jsコンソールに次のように表示されます:

_OPTIONS /books 200 1ms - 161b 
_

query()メソッドを使用すると正常に機能します-Nodeコンソールには次のように表示されます:

_GET /books 200 1ms - 228b
_

私はこの時点で数時間スタックしていて、以下のバリエーションを試していますが、常にPOSTではなくOPTIONSリクエストになります(これはAngularドキュメント)_$save_メソッド。

AngularJS Webアプリ

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 AP​​I

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

この行を私の構成関数_delete $httpProvider.defaults.headers.common["X-Requested-With"];_に入れてみましたが、変更はありませんでした。

私はAngular/Nodeのプロではありませんが、現在、それがクロスドメインであることと関係があると考えています。そして、私が言ったように、私はCORSの専門家ではありません。

前もって感謝します。

24
Tom P.

自分の質問に答えるのは嫌なことかもしれませんが、これを投稿してから数日後に問題を見つけました。

すべては、ブラウザーがCORSを管理する方法にかかっています。 「単純」ではないJavaScriptでクロスドメインリクエストを作成する場合(つまり、GETリクエスト-query()関数が機能した理由を説明する)、ブラウザは指定されたURL /にHTTP OPTIONSリクエストを自動的に作成します。 「プリフライト」リクエストまたは「プロミス」と呼ばれるURI。リモートソースが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);
});

うまくいけば、これが同じページでこのページに遭遇した人を助けるでしょう。

43
Tom P.

私は実際にはこれを試しませんでしたが、$ save要求を処理する方法をRessourceに伝えるには十分ではないでしょうか?

$resource('http://mywebserver\\:1337/books/:bookId', { bookId: '@bookId' }, {save: {method: 'POST'});
1
mausberger