angular: HttpClient do not detect header params
I’m submitting a…
[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
HttpClient do not detect the custom header params that are sent from the API. While using Http we were able to access it and make use of it.
Expected behavior
HttpClient should detect the custom headers and make them accessible by the code. We tried with both Http & HttpClient. I works fine with Http but not with HttpClient.
Minimal reproduction of the problem with instructions
We used both Http & HttpClient to fetch the header params. Http returns the header, but HttpClient doesn’t.
constructor(private http: Http, private httpClient: HttpClient) {}
getContent() {
const url = '<API URL>';
return this.http.post(url, data)
.map((res: Response) => {
console.log('http content', res);
});
return this.httpClient.post(url, data, { observe: 'response' })
.map((res: HttpResponse<any>) => {
console.log('httpClient content',res);
});
}
When checked in console, http returns the response with headers but httpClient returns an empty array. When checked in networks tab of browser inspector, it displays all the header parameters that are sent from API.
The server has the following CORS options: origin: ‘*’, methods: ‘GET,HEAD,PUT,PATCH,POST,DELETE’, allowedHeaders: ‘Origin,X-Requested-With,x-access-token,Content-Type,Authorization,Accept,tokenkey’, exposedHeaders: ‘Content-Type,Authorization,tokenkey’
What is the motivation / use case for changing the behavior?
I want to access the token key that is sent from the API and store it to authorize and validate the user. I am unable to get the tokenkey from the API.
Environment
Angular version: 4.4.6
I created a dummy project with 5.0.0 as well. It didn't work.
Browser:
- [x] Chrome (desktop) version 62.0.3202.94
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: 6.11.2
- Platform: Windows
Others:
@angular/cli: 1.4.9
node: 6.11.2
os: win32 x64
@angular/animations: 4.4.6
@angular/common: 4.4.6
@angular/compiler: 4.4.6
@angular/core: 4.4.6
@angular/forms: 4.4.6
@angular/http: 4.4.6
@angular/platform-browser: 4.4.6
@angular/platform-browser-dynamic: 4.4.6
@angular/router: 4.4.6
@angular/service-worker: 1.0.0-beta.16
@angular/cli: 1.4.9
@angular/compiler-cli: 4.4.6
@angular/language-service: 4.4.6
typescript: 2.3.4
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 14
- Comments: 38 (11 by maintainers)
@GAlexMES From the screenshot you’re definitely misusing it.
Access-Control-Allow-Headers
must be provided in response ofOPTIONS
request (pre-flight);Access-Control-Expose-Headers
must be provided in response ofPOST
request.They’ll never show up in same response.
+1 It also doesn’t work with an angular 5.0.0 Projekt and Firefox 57.0.
The console shows something like:
But the Firefox Dev Tools shows the following Response Headers:
@MyGitHubTests please try https://github.com/angular/angular/issues/5237#issuecomment-239174349
OK, found the problem. Caused by ourselves, of course 😉
We were inspecting the REQUEST headers while we should instead have been looking at RESPONSE headers.
This works (in the intercept(…) method):
The reason for our confusion is probably that (from our point of view) the signature of intercept(…) changed a bit. In 4.1.3 (custom intercept method that we created ourselves):
intercept(observable: Observable<Response>): Observable<Response> {
In 5.1.1:intercept(req: HttpRequest<any>, next: any): Observable<any> {
So previously we were only working with an http response in our interceptor, now we both have the http request and the ‘next’ chain. When inspecting the http response in an interceptor, we should (obviously…) hook into the next.handle(…) pipe.
I’m afraid I’m seeing similar issues after moving to Angular 5.1.1
Both
version
andserviceName
stay empty.One of the calls that is expected to be valid in this case and start checking for
validVersion
looks like this: RequestResponse
This seems to be matching the
XMLHttpRequest
standard for required headers, yet I’m seeing nothing butnull
s in my console when doing this:result:
version null
serviceName null
This seemed to work when we were using version Angular 4.1.3, where we received results similar to this when testing this specific service call:
version 1
serviceName service-frontend-log
Any ideas @trotyl? We’ve been careful to examine if we weren’t missing any headers to make this work but couldn’t spot any. We’re afraid we’ve actually found a regression bug between Angular 4.1.3 and Angular 5.1.1.
@MyGitHubTests You did not even set
Access-Control-Expose-Headers
header, how should it work?Fixed by specifying
observe: response
in request’s options. More details: https://angular.io/guide/http#reading-the-full-responseCan we close this issue, I’m quite sure there is no issue anymore. You can parse headers as of now and the main issues people keep talking about are
CORS
related on their own backends, not in the Angular frontend.@JayendharPrakash Can you close this as resolved please?
For those this could help. I forgot to set ‘access-control-expose-headers’ in the server. This is my extract of expressjs returning the answer of a login post async (req: Request, res: Response, next: NextFunction) => { … … return res .header(‘access-control-expose-headers’, ‘x-auth-token’) .header(‘x-auth-token’, ‘cocco’) .status(200) .send(account); }
Another way of doing this (when using expressjs) is to set the cors as such const corsOptions: cors.CorsOptions = { … exposedHeaders: [‘x-auth-token’] }; … const instance: Express = express(); instance.use(require(‘cors’)(corsOptions)); …
I prefer the first method as this gives me choice when that header is allowed (and used).
It does seem to work on regular HttpClient calls, but not in an HttpInterceptor. We’re on Angular 5.1.1.
Http call with HttpClient:
HttpInterceptor code (part of it):
Http response from the backend:
Console logging:
(that the request passes through the interceptor twice: once as OPTIONS pre-flight and once as GET)
The logging from the HttpClient call includes Content-Type and our custom response headers. The logging from the HttpInterceptor only includes the Content-Type response header. As @Bjeaurn indicated, this did work on Angular 4.1.3.
Giving it a bit more thought, I’m wondering. Do we have access to both the http request and http response in an interceptor? We might be looking at the request instead of the response 😉
All CORS headers are added in response, that’s not related to Angular, and you’re adding them in wrong place.
I’m going to leave this issue open for now in a “needs reproduction” state, but I expect @Bjeaurn is correct - this is largely related to CORS issues and header visibility, and not a bug in Angular.
If anyone has a reproduction showing headers which should be available on the response per CORS but are missing, please add it here and we can look into it. Otherwise, this issue will be closed eventually.
(apologies in advance for formatting as I am on mobile) I figured it out.
The map method of the response interceptor :
import {map} from ‘rxjs/operators; import {HttpResponse} from’ @angular/common/http; … return next.handle(req).pipe( map((resp: HttpResponse<any>) => { if(resp.headers) { //your logic for headers } }) ) ; …
*Note that you still have to set the Access-Control-Expose-Headers header explicitly on the backend.
@MyGitHubTests https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS