angular2 / http获取201响应的位置头 [英] angular2/http get location header of 201 response

查看:3483
本文介绍了angular2 / http获取201响应的位置头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我成功完成了angular2英雄之旅入门教程。然后我建立一个api基于symfony3,FosRestBundle和BazingaHateoasBundle作为后端。
现在几乎一切正常,但在创建新项目时,我无法从响应中获取位置标头,以加载新创建的项目。



这是我的英雄服务:

  import {Injectable} fromangular2 / core 
import {Hero} from./hero;
import {Http,Headers,RequestOptions,Response} fromangular2 / http;
import {Observable} fromrxjs / Observable;
importrxjs / Rx;

@Injectable()
export类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结果在控制台
。 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});

返回this._http.post(this._heroesUrl,body,options)
//创建Hero,但无法从Location头获取URL!
.map((res:Response)=> this._http.get(res.headers.get('Location'))。map((res:Response)=> res.json
.catch(this.handleError)

}

private handleError(error:Response){
//在现实世界的应用程序中,我们可能发送错误到一些远程日志基础结构
//而不是只是记录到控制台
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结果在控制台
。 catch(this.handleError);
}
}

所以当我调用addHero方法时,创建新的Hero,并返回一个没有正文的响应,但是设置了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
位置:http://tour-of-heros.loc/app_dev.php/api/heroes/3
服务器: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。但没有位置。



我知道应该也可以通过将新创建的数据添加到响应的主体来解决问题,但这不是真的

解决方案



<您应该使用 flatMap 运算符而不是映射

  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 
pre>

如果你在调用的服务器端手,你可以更新这个头,你想在客户端使用的头(<$ c $



我调试了请求,特别是 XhrBackend 实际执行请求并从XHR对象获取响应的类。标头不是由代码返回: _xhr.getAllResponseHeaders()。在我的例子中,我只有Content-Type。



查看此链接: https://github.com/angular/angular/blob/master/modules/angular2/src/http/backends /xhr_backend.ts#L42



从以下问题:


跨源资源共享规范过滤由getResponseHeader()为非同源请求公开的头。并且该规范禁止访问除简单响应头字段(即,高速缓存控制,内容语言,内容类型,过期,最后修改和Pragma)之外的任何响应头字段:


有关详情,请参阅此问题:




I finished successfully the angular2 "tour of heroes" starter tutorial. Then I build an api based on symfony3, FosRestBundle and BazingaHateoasBundle as backend. Now nearly everything works, but on creating new items I'm not able to get the "Location" header from the response to load the newly created Item.

Here is my Hero Service:

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

So when I'm calling the addHero method, a new Hero is created and a 201 response is returned without a body, but with the Location header set:

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

The problem is, that the res.headers.get('Location') didn't get the Location header from the response. After some debugging it seems to be that the res.headers just provides two headers Cache-Control and Content-Type. But no Location.

I knew it should be also possible to solve the problem by adding the newly created data to body of the response, but this is not really the way I want to solve this.

Thank you in advance!

解决方案

You should use the flatMap operator instead of the map one:

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)

Edit

Regarding your header problem.

I think that your problem is related to CORS. I think that the preflighted request should return the headers to authorize in the Access-Control-Allow-Headers in its response. Something like that:

Access-Control-Allow-Headers:location

If you have the hand on the server side of the call, you could update this header with the headers you want to use on the client side (in your caseLocation`).

I debugged the request and specially within the XhrBackend class that actually executes the request and gets the response from the XHR object. The header isn't returned by the code: _xhr.getAllResponseHeaders(). In my case, I only have the Content-Type one.

See this link: https://github.com/angular/angular/blob/master/modules/angular2/src/http/backends/xhr_backend.ts#L42.

From the following question:

Cross-Origin Resource Sharing specification filters the headers that are exposed by getResponseHeader() for non same-origin requests. And that specification forbids access to any response header field other except the simple response header fields (i.e. Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma):

See this question for more details:

这篇关于angular2 / http获取201响应的位置头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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