diff --git a/packages/common/http/src/xhr.ts b/packages/common/http/src/xhr.ts index c7123ae792..0d14a01bfa 100644 --- a/packages/common/http/src/xhr.ts +++ b/packages/common/http/src/xhr.ts @@ -191,6 +191,14 @@ export class HttpXhrBackend implements HttpBackend { // The parse error contains the text of the body that failed to parse. body = { error, text: body } as HttpJsonParseError; } + } else if (!ok && req.responseType === 'json' && typeof body === 'string') { + try { + // Attempt to parse the body as JSON. + body = JSON.parse(body); + } catch (error) { + // Cannot be certain that the body was meant to be parsed as JSON. + // Leave the body as a string. + } } if (ok) { diff --git a/packages/common/http/test/xhr_spec.ts b/packages/common/http/test/xhr_spec.ts index 6c37619333..4c76dce6ad 100644 --- a/packages/common/http/test/xhr_spec.ts +++ b/packages/common/http/test/xhr_spec.ts @@ -17,7 +17,7 @@ import {MockXhrFactory} from './xhr_mock'; function trackEvents(obs: Observable>): HttpEvent[] { const events: HttpEvent[] = []; - obs.subscribe(event => events.push(event)); + obs.subscribe(event => events.push(event), err => events.push(err)); return events; } @@ -92,6 +92,13 @@ export function main() { const res = events[1] as HttpResponse<{data: string}>; expect(res.body !.data).toBe('some data'); }); + it('handles a json error response', () => { + const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); + factory.mock.mockFlush(500, 'Error', JSON.stringify({data: 'some data'})); + expect(events.length).toBe(2); + const res = events[1] as any as HttpErrorResponse; + expect(res.error !.data).toBe('some data'); + }); it('handles a json string response', () => { const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); expect(factory.mock.responseType).toEqual('text');