代码改变世界

ABP throw UserFriendlyException() 源码

2020-07-08 16:10  qgbo  阅读(1835)  评论(0编辑  收藏  举报

ABP  throw UserFriendlyException() ,会让前端弹出界面。

实现的话,首先 throw UserFriendlyException()  并不会在后端产生真正的异常,否则就是500 错误了。

ABP 的默认实现,是所有的请求,包裹在result { },里面,这个是ABP 封装的(可以去掉)

这个是怎么在前端解析出来实际的响应内容呢?  前端有 abpHttpInterceptor.js  这在前端启动的时候注册的一个HttpInterceptor。

里面有这个方法,来解析出来实际的 response.  这个Interceptor 会在发送请求的时候拦截,响应回来的时候拦截,也相当于一节管道了。

 1 AbpHttpConfiguration.prototype.handleAbpResponse = function (response, ajaxResponse) {
 2         var newResponse;
 3         if (ajaxResponse.success) {
 4             newResponse = response.clone({
 5                 body: ajaxResponse.result
 6             });
 7             if (ajaxResponse.targetUrl) {
 8                 this.handleTargetUrl(ajaxResponse.targetUrl);
 9                 ;
10             }
11         }
12         else {
13             newResponse = response.clone({
14                 body: ajaxResponse.result
15             });
16             if (!ajaxResponse.error) {
17                 ajaxResponse.error = this.defaultError;
18             }
19             this.logError(ajaxResponse.error);
20             this.showError(ajaxResponse.error);
21             if (response.status === 401) {
22                 this.handleUnAuthorizedRequest(null, ajaxResponse.targetUrl);
23             }
24         }
25         return newResponse;
26     };

 再来看后端怎么实现的。

后端有一个AbpMvcAuditFilter.cs  他的 一部分代码在这里。通过这儿,可以看出这里的Filter把  filterContext.Result 进行改动。我们也可以在这里加上一层。

这里是Audit 的部分,原理类似。

            if (_auditingConfiguration.SaveReturnValues && filterContext.Result != null)
            {
                switch (filterContext.Result)
                {
                    case AbpJsonResult abpJsonResult:
                        if (abpJsonResult.Data is AjaxResponse ajaxResponse)
                        {
                            auditData.AuditInfo.ReturnValue = _auditSerializer.Serialize(ajaxResponse.Result);
                        }
                        else
                        {
                            auditData.AuditInfo.ReturnValue = _auditSerializer.Serialize(abpJsonResult.Data);
                        }
                        break;

                    case JsonResult jsonResult:
                        auditData.AuditInfo.ReturnValue = _auditSerializer.Serialize(jsonResult.Data);
                        break;

                    case ContentResult contentResult:
                        auditData.AuditInfo.ReturnValue = contentResult.Content;
                        break;

                }
            }

 在  .Netcore api 中生成的 swagger 文档中,前端Angular 在拦截器中添加如下 处理

return next.handle(req1).pipe(tap(() => { },
            (err: any) => {
                if (err instanceof HttpErrorResponse) {
                    if (err.status !== 401) {
                        console.error(err.message);
                        return;
                    }
                    this.router.navigate(['login']);
                }
            }));

  handle(req),执行的就是请求后端。 这里的返回是一个Observable 对象。可以pipe或者 subscribe().

pipe里可以有一些 operator.  也就是一些方法。 scan()是一个累加器,会接受一个一个的值,然后把这些值一个一个的算出一个结果来,也就是会记住历史,累计历史。

他的初始值是一个参数:seed.

https://stackblitz.com/edit/dcm2d1?file=index.ts

下面的代码,说明了merge和contact的差别

import { merge, interval, concat } from 'rxjs';
import { take, tap } from 'rxjs/operators';

const timer1 = interval(1000).pipe(tap(t=>console.log('timer1')),take(3));
const timer2 = interval(2000).pipe(tap(t=>console.log('timer2')));
const timer3 = interval(500).pipe(tap(t=>console.log('timer3')));
const concurrent = 2; // the argument
const merged = merge(timer1, timer2, timer3); // 可以替换为 contact 看看
merged.subscribe(x => console.log(x));