Angular2 rxjs http.request.catch has strange behav

2019-05-06 04:51发布

问题:

My http service does not catch correctly some http errors. The catch method has 2 different response objects ( see below ).

private fireRequest(request: Request): Observable<any> {
    return this.http.request(request)
    .switchMap((response: Response) => {
        const responseData = response.json() || [];
        return Observable.of(responseData);
    })
    .catch((response: Response) => {
        const res2 = response.json();
        // filters http errors from status 0 errors
        if (response.status && response.status > 0) {
            const res = response.json();
            return Observable.of<any>(res);
        }
        const unexpectedNetworkError = new 
              Error('commons.unexpected_network');
        return Observable.throw(unexpectedNetworkError);
    })
}

Strange error behaviour. ( even in chrome network tab i do not see the http body )

// catch 404 error
{ 
  headers: Headers,
  ok: false,
  status: 0,
  statusText : "",
  type : 3,
  url : null,
  _body : ProgressEvent
}

Correct error behaviour

// catch 401 error
{ 
  headers: Headers,
  ok: false,
  status: 401,
  statusText : "Unauthorized",
  type : 2,
  url : http://api.service/users,
  _body : { // json body}
}

回答1:

I found out the problem regards the browser and its CORS behaviour.

a) Succefull call

BROWSER                  SERVER
    | ------ preflight ---> |
    | <-- allow GET, PUT -- |
    | ------- GET req ----> |
    | <------ GET res ----- |

b) Failed call with backed response 404 instead of 200

BROWSER                SERVER
    | ---- preflight ----> |
    | <------ 404 -------- |
    |                      |
    |                      |

c) No intenet connection, no response from server

BROWSER                SERVER
    | ---- preflight ----> X
    |                      |
    |                      |
    |                      |

Whenever you make an api call to a non existing ruote, the browser sends a preflight request (b).

Depening on your backend error handling strategy you could receive:

1) Http 404 code with error details in the body In this case the browser returns a generic error with http status code 0 without the actual server's payload. The second call is never made because there is no sense in doing it since the preflight went wrong.

2) Http 200 code for the preflight and 404 for the actual call. In this case everything works fine.

The problem remains if there is no internet connection.