7

angular2 の「ツアー オブ ヒーローズ」スターター チュートリアルを無事終了しました。次に、バックエンドとして symfony3、FosRestBundle、BazingaHateoasBundle に基づいて API を構築します。ほとんどすべてが機能するようになりましたが、新しいアイテムを作成すると、応答から「場所」ヘッダーを取得して、新しく作成されたアイテムをロードできません。

これが私のヒーローサービスです:

import {Injectable} from "angular2/core";
import {Hero} from "./hero";
import {Http, Headers, RequestOptions, Response} from "angular2/http";
import {Observable} from "rxjs/Observable";
import "rxjs/Rx";

@Injectable()
export class HeroService {

    constructor(private _http:Http) {
    }

    private _apiUrl = 'http://tour-of-heros.loc/app_dev.php/api'; // Base URL
    private _heroesUrl = this._apiUrl + '/heroes';  // URL to the hero api


    getHeroes() {
        return this._http.get(this._heroesUrl)
            .map(res => <Hero[]> res.json()._embedded.items)
            .do(data => console.log(data)) // eyeball results in the console
            .catch(this.handleError);
    }

    addHero(name:string):Observable<Hero> {

        let body = JSON.stringify({name});

        let headers = new Headers({'Content-Type': 'application/json'});
        let options = new RequestOptions({headers: headers});

        return this._http.post(this._heroesUrl, body, options)
            // Hero is created, but unable to get URL from the Location header!
            .map((res:Response) => this._http.get(res.headers.get('Location')).map((res:Response) => res.json()))
            .catch(this.handleError)

    }

    private handleError(error:Response) {
        // in a real world app, we may send the error to some remote logging infrastructure
        // instead of just logging it to the console
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }

    getHero(id:number) {
        return this._http.get(this._heroesUrl + '/' + id)
            .map(res => {
                return res.json();
            })
            .do(data => console.log(data)) // eyeball results in the console
            .catch(this.handleError);
    }
}

したがって、addHero メソッドを呼び出すと、新しいヒーローが作成され、ボディなしで 201 応答が返されますが、Location ヘッダーが設定されています。

Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 0
Content-Type: application/json
Date: Tue, 29 Mar 2016 09:24:42 GMT
Keep-Alive: timeout=5, max=100
Location: http://tour-of-heros.loc/app_dev.php/api/heroes/3
Server: Apache/2.4.10 (Debian)
X-Debug-Token: 06323e
X-Debug-Token-Link: /app_dev.php/_profiler/06323e
access-control-allow-credentials: true
access-control-allow-origin: http://172.18.0.10:3000

問題は、res.headers.get('Location')応答から Location ヘッダーを取得できなかったことです。いくつかのデバッグの後、res.headersは Cache-Control と Content-Type の 2 つのヘッダーのみを提供しているようです。しかし、場所はありません。

新しく作成されたデータを応答の本文に追加することで問題を解決することも可能であることはわかっていましたが、これは実際に解決したい方法ではありません。

前もって感謝します!

4

2 に答える 2

11

flatMap次の演算子の代わりに演算子を使用する必要がありますmap

return this._http.post(this._heroesUrl, body, options)
        .flatMap((res:Response) => {
          var location = res.headers.get('Location');
          return this._http.get(location);
        }).map((res:Response) => res.json()))
        .catch(this.handleError)

編集

ヘッダーの問題について。

あなたの問題はCORSに関連していると思います。Access-Control-Allow-Headersプリフライトされたリクエストは、そのレスポンスで承認するヘッダーを返す必要があると思います。そんな感じ:

Access-Control-Allow-Headers:location

呼び出しのサーバー側に手がある場合は、このヘッダーをクライアント側で使用するヘッダーで更新できます ( in your caseLocation`)。

XhrBackendリクエストをデバッグし、実際にリクエストを実行して XHR オブジェクトからレスポンスを取得するクラス内で特別にデバッグしました。ヘッダーはコードによって返されません: _xhr.getAllResponseHeaders(). 私の場合、私は Content-Type のものしか持っていません。

次のリンクを参照してください: https://github.com/angular/angular/blob/master/modules/angular2/src/http/backends/xhr_backend.ts#L42

次の質問から:

Cross-Origin Resource Sharing 仕様は、同一オリジンでないリクエストに対して getResponseHeader() によって公開されるヘッダーをフィルタリングします。また、その仕様では、単純な応答ヘッダー フィールド (つまり、Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、および Pragma) 以外の応答ヘッダー フィールドへのアクセスを禁止しています。

詳細については、この質問を参照してください。

于 2016-03-29T10:38:37.280 に答える
4

私のせい!

https://github.com/angular/angular/issues/5237およびhttp://www.aaron-powell.com/posts/2013-11-28-accessing-location-header-in-cors-responseを読んだ後。 html 、NelmioCorsBundle ( https://github.com/nelmio/NelmioCorsBundle/issues/9 )の CORS 構成に何か問題があるに違いないことを認識しています。手っ取り早い修正としてexpose_headers: ['Origin','Accept','Content-Type', 'Location']、symfony の設定に追加しました:

nelmio_cors:
    paths:
        '^/api/':
            allow_credentials: true
            origin_regex: true
            allow_origin: ['*']
            allow_headers: ['Origin','Accept','Content-Type', 'Location']
            allow_methods: ['POST','GET','DELETE','PUT','OPTIONS']
            max_age: 3600

後:

nelmio_cors:
    paths:
        '^/api/':
            allow_credentials: true
            origin_regex: true
            allow_origin: ['*']
            allow_headers: ['Origin','Accept','Content-Type', 'Location']
            allow_methods: ['POST','GET','DELETE','PUT','OPTIONS']
            expose_headers: ['Origin','Accept','Content-Type', 'Location']
            max_age: 3600

そして今、それは魅力のように機能します。

したがって、これは角度の問題ではなく、実際に解決できることはありませんでした。ごめん!同様の CORS 問題に遭遇したすべての人のために、これを保持します。

貢献してくれたすべての人に感謝します

于 2016-03-29T11:35:13.347 に答える