如何使用自定义Aurelia http-fetch-client拦截器正确使用responseError?

时间:2017-07-19 05:42:40

标签: typescript aurelia aurelia-cli aurelia-framework aurelia-fetch-client

我正在使用TypeScript处理Aurelia CLI项目,并使用aurelia-fetch-client对.NET Core / Web API后端进行HTTP调用。

服务器通过返回ApiError JSON结果作为API响应的主体来标准化未处理的异常,状态代码在5xx范围内。

在客户端上,我想使用拦截器执行客户端发布这些错误,但添加拦截器正在以不合需要的方式更改控制流。

这是main.ts中的相关配置:

function configureContainer(container: Container) {
    const http = new HttpClient();
    http.configure((config: HttpClientConfiguration) => {
        config.useStandardConfiguration()
            .withBaseUrl("/api/")
            .withInterceptor(new ApiErrorInterceptor(container.get(EventAggregator)));
    });

    container.registerInstance(HttpClient, http);
}

这是拦截器:

import { autoinject } from "aurelia-framework";
import { EventAggregator } from "aurelia-event-aggregator";
import { Interceptor } from "aurelia-fetch-client";

@autoinject
export class ApiErrorInterceptor implements Interceptor {
    constructor(private readonly _aggregator: EventAggregator) {
    }

    responseError(error: any) {
        // do something with the error            

        return error;
    }
}

如果未添加自定义拦截器,则会在Chrome中将非OK响应记录为错误,如下所示:

Unhandled rejection (<{}>, no stack trace)

但是如果添加了拦截器,则promises不再导致未处理的拒绝错误,并且调用代码继续,就好像promise已解决,这不是我们想要的,因为它引入了对控件的巨大更改整个应用程序的流程。

如何实现responseError()处理程序,以便控制流程像以前一样工作?这甚至是可能的,还是我误解了这个处理程序的目的?

我尝试重新抛出返回的错误,但这不会针对Interceptor接口进行编译。我应该在response()代替这样做吗?例如?

编辑:

这是我们最终使用的内容,在更详细地查看了Fetch源和相关的Aurelia源之后。它仅在response()处理程序中处理基于服务器的错误,仅在responseError()中处理基于客户端的连接错误。

import { autoinject } from "aurelia-framework";
import { EventAggregator } from "aurelia-event-aggregator";
import { Interceptor } from "aurelia-fetch-client";
import { TypedJSON } from "typedjson-npm";
import { EventNames } from "../model/EventNames";
import { ApiError } from "../model/ApiError";

@autoinject
export class ApiErrorInterceptor implements Interceptor {
    constructor(private readonly _aggregator: EventAggregator) {
    }

    async response(response: Response, request?: Request) {
        if (!response.ok) {
            // publish an error for the response
            const apiError = await this.translateToApiError(response.clone());
            if (apiError) {
                this._aggregator.publish(EventNames.apiError, apiError);
            }
        }

        return response;
    }

    responseError(error: any) {
        // publish errors resulting from connection failure, etc
        if (error instanceof Error) {
            const apiError = new ApiError();
            apiError.statusCode = 0;
            apiError.isError = true;
            apiError.message = error.message;

            this._aggregator.publish(EventNames.apiError, apiError);
        }

        return error;
    }

    private async translateToApiError(response: Response): Promise<ApiError> {
        let apiError: ApiError | undefined = undefined;
        const text = await response.text();

        if (text) {
            apiError = TypedJSON.parse(text, ApiError);
        }

        if (!apiError) {
            apiError = this.getHttpError(response);
        }

        return apiError;
    }

    private getHttpError(response: Response): ApiError {
        const apiError = new ApiError();
        apiError.isError = true;
        apiError.statusCode = response.status;
        apiError.message = "Unknown HTTP Error";

        switch (apiError.statusCode) {
            case 400:
                apiError.message = "Bad Request";
                break;

            case 401:
                apiError.message = "Unauthorized Access";
                break;

            case 404:
                apiError.message = "Not Found";
                break;
        }

        if (apiError.statusCode >= 500 && apiError.statusCode < 600) {
            apiError.message = "Internal Server Error";
        }

        return apiError;
    }
}

2 个答案:

答案 0 :(得分:0)

使用return Promise.reject(error);代替return error;正在使用您的代码编译并按预期工作。返回错误假定您已解决响应并将返回值传递给已解析的代码路径,这就是您看到不良行为的原因。

答案 1 :(得分:0)

responseError的错误参数是any,因此请确保它是您认为的。在我的情况下,我期待失败的响应,但得到了一个被捕获的TypeError异常。这是我的拦截器:

responseError(response: any): Promise<Response> {
    if (response instanceof Response) {
        return response.json().then((serverError: ServerError) => {

            // Do something with the error here.

            return Promise.reject<Response>(serverError.error);
        }); 
    }
}

我也遇到过在.NET Core应用程序中配置异常处理中间件的问题。就我而言,UseDeveloperExceptionPage在fetch客户端中导致CORS错误。听起来这与您的问题不一样,但您可以将您的配置与我的here进行比较。