.NET中间件以及VUE拦截器联合使用

打印 上一主题 下一主题

主题 886|帖子 886|积分 2658

.NET中间件以及VUE拦截器联合使用

工作中遇见的问题,边学边弄,记录一下

Vue的UI库使用的是antvue 3.2.9版本的。


  • 业务逻辑

  • 特性
  1. //特性
  2.     public class ModelEsignNameAttribute : Attribute
  3.     {
  4.         public ModelEsignNameAttribute(string nameProp, string id, string reversion = "", ModelESignType eSignType = ModelESignType.Modeling, string middleModelId = "")
  5.         {
  6.         }
  7.     }
复制代码

  • 接口加上特性
  1.         /// <summary>
  2.         ///  添加或者修改方法
  3.         /// </summary>
  4.         /// <param name="input"></param>
  5.         /// <returns></returns>
  6.                 //特性上添加参数的地址
  7.         [ModelEsignName("Bolg.BolgBaseEditDto.BolgName", "Document.Id", "Bolg.BolgRevision")]
  8.         public async Task<Output> CreateOrUpdate(CreateOrUpdateBolgInput input)
  9.         {
  10.             var doc = await _XXXXManager.FindRdoById(input.Bolg.Id.Value);
  11.             // 文档id为空,新增
  12.             if (doc == null || !input.Bolg.BolgBaseId.HasValue)
  13.             {
  14.                 return await this.Create(input.Bolg);
  15.             }
  16.             // 更新
  17.             return await this.Update(input.Bolg);
  18.         }
复制代码

  • 中间件代码
  1. namespace GCT.MedPro.Middleware
  2. {
  3.     public class ModelESignCheckMiddleware : IMiddleware
  4.     {
  5.         
  6.                 #region 依赖注入等内容
  7.                         ....
  8.         #endregion
  9.         
  10.         public async Task InvokeAsync(HttpContext context, RequestDelegate next)
  11.         {
  12.             if (await ShouldCheckESign(context))
  13.             {
  14.                 // 不需要电子签名
  15.                 await next(context);
  16.             }
  17.         }
  18.         /// <summary>
  19.         /// 是否需要拦截
  20.         /// </summary>
  21.         /// <param name="actionContext"></param>
  22.         /// <returns></returns>
  23.         private async Task<bool> ShouldCheckESign(HttpContext actionContext)
  24.         {
  25.             var whetherSignature = true;
  26.             var request = actionContext.Request;//获取请求值
  27.             var currentUser = actionContext.User.Identity.Name;
  28.             var serviceAction = actionContext
  29.                     .GetEndpoint()?
  30.                     .Metadata
  31.                     .GetMetadata<ControllerActionDescriptor>();
  32.             if (serviceAction == null)
  33.             {
  34.                 return whetherSignature;
  35.             }
  36.             //通过接口特性来筛选是否需要进行拦截
  37.             var attrObj = serviceAction.MethodInfo.CustomAttributes
  38.                 .FirstOrDefault(x => x.AttributeType == typeof(ModelEsignNameAttribute));
  39.             if (attrObj == null)
  40.             {
  41.                 return whetherSignature;
  42.             }
  43.             
  44.             string inputbody = default;
  45.             actionContext.Request.EnableBuffering();
  46.             
  47.             //Post请求获取请求参数,转换JSON
  48.             if (request.Method.ToLower().Equals("post"))
  49.             {
  50.                 var requestReader = new StreamReader(actionContext.Request.Body);
  51.                 var body = await requestReader.ReadToEndAsync();
  52.                 inputbody = UpperFirst(body); //首字母大写    全局搜索可得下方有
  53.             }
  54.             else   //GET请求以及其他方式获取
  55.             {
  56.                 var reqString = request.QueryString.Value.Remove(0, 1);
  57.                 string[] parts = reqString.Split("&");
  58.                 JObject json = new JObject();
  59.                 foreach (string part in parts)
  60.                 {
  61.                     String[] keyVal = part.Split("=");
  62.                     json.Add(keyVal[0], keyVal[1]);
  63.                 }
  64.                 inputbody = JsonConvert.SerializeObject(json);
  65.                 inputbody = UpperFirst(inputbody);
  66.             }
  67.             
  68.             var inputObj = JObject.Parse(inputbody);//转换JObject
  69.             
  70.             
  71.             #region 获取特性传入的参数,,总五位参数
  72.                         var actionName = serviceAction.ActionName;
  73.             var namePath = attrObj.ConstructorArguments[0].Value.ToString();
  74.             var idPath = attrObj.ConstructorArguments[1].Value.ToString();
  75.             var revsionPath = attrObj.ConstructorArguments[2].Value.ToString();
  76.             var typePath = (ModelESignType)attrObj.ConstructorArguments[3].Value;
  77.             var middlePath = attrObj.ConstructorArguments[4].Value.ToString();
  78.                 #endregion
  79.             
  80.             var middleModelId = GetValueName(inputObj, middlePath);//通过JObject获取对应值
  81.             //接口控制器名称
  82.             var typeName = serviceAction.ControllerTypeInfo.FullName;
  83.             //重置请求Body指针  
  84.             actionContext.Request.Body.Position = 0;
  85.             //验证方法,自己写个,自已业务的处理验证
  86.             var output = await CheckSign(middleModelId);
  87.             
  88.             if (!output.SignStatus)
  89.             {
  90.                 actionContext.Request.EnableBuffering();
  91.                 Stream originalBody = actionContext.Response.Body;
  92.                 try
  93.                 {
  94.                     using (var ms = new MemoryStream())
  95.                     {
  96.                         //修改响应状态麻420
  97.                         actionContext.Response.Body = ms;
  98.                         actionContext.Response.StatusCode = 420;
  99.                         ms.Position = 0;
  100.                         //写入数据
  101.                         var responseBody = TextJosn.JsonSerializer.Serialize(output);
  102.                         var memoryStream = new MemoryStream();
  103.                        
  104.                         var sw = new StreamWriter(memoryStream);
  105.                          //自己编辑的实体写入响应体
  106.                         sw.Write(responseBody);
  107.                         sw.Flush();
  108.                
  109.                         //重置响应指针
  110.                         memoryStream.Position = 0;
  111.                         //复制到原body上
  112.                         await memoryStream.CopyToAsync(originalBody);
  113.                     }
  114.                 }
  115.                 finally
  116.                 {
  117.                     actionContext.Response.Body = originalBody;
  118.                     actionContext.Request.Body.Position = 0;
  119.                 }
  120.                 whetherSignature = false;
  121.             }
  122.             else
  123.             {
  124.                 if (!string.IsNullOrWhiteSpace(output.ErrorMessage))
  125.                 {
  126.                     var serializerSettings = new JsonSerializerSettings
  127.                     {
  128.                         // 设置为驼峰命名
  129.                         ContractResolver = new Newtonsoft.Json.Serialization
  130.                             .CamelCasePropertyNamesContractResolver()
  131.                     };
  132.                     //错误友好提示,适配中间件中抛出错误,修改响应体
  133.                     var exception = new UserFriendlyException(output.ErrorMessage);
  134.                     actionContext.Response.StatusCode = 500;
  135.                     actionContext.Response.ContentType = "application/json; charset=utf-8";
  136.                     //写入
  137.                     await actionContext.Response.WriteAsync(
  138.                     JsonConvert.SerializeObject(
  139.                         new AjaxResponse(
  140.                             _errorInfoBuilder.BuildForException(exception),
  141.                             true
  142.                              ), serializerSettings
  143.                          )
  144.                     );
  145.                     whetherSignature = false;
  146.                 }
  147.             }
  148.             return whetherSignature;
  149.         }
  150.         
  151.         
  152.                 //取出json的Name值
  153.         private string GetValueName(JObject inputObj, string path)
  154.         {
  155.             string result = null;
  156.             if (!string.IsNullOrWhiteSpace(path))
  157.             {
  158.                 result = inputObj.SelectToken(path).ToObject<string>();
  159.             }
  160.             return result;
  161.         }
  162.         /// <summary>
  163.         /// Json字符串首字母转大写
  164.         /// </summary>
  165.         /// <param name="strJsonData">json字符串</param>
  166.         /// <returns></returns>
  167.         public static string UpperFirst(string strJsonData)
  168.         {
  169.             MatchCollection matchCollection = Regex.Matches(strJsonData, "\\"[a-zA-Z0-9]+\\"\\s*:");
  170.             foreach (Match item in matchCollection)
  171.             {
  172.                 string res = Regex.Replace(item.Value, @"\b[a-z]\w+", delegate (Match match)
  173.                 {
  174.                     string val = match.ToString();
  175.                     return char.ToUpper(val[0]) + val.Substring(1);
  176.                 });
  177.                 strJsonData = strJsonData.Replace(item.Value, res);
  178.             }
  179.             return strJsonData;
  180.         }
  181.     }
  182. }
复制代码

  • Vue拦截器,拦截失败的响应,状态码为420的,中间件修改的响应的状态码
  1. import { AppConsts } from '/@/abpPro/AppConsts';
  2. import { abpService } from '/@/shared/abp';
  3. import { Modal } from 'ant-design-vue';
  4. import axios, { AxiosResponse } from 'axios';
  5. import abpHttpConfiguration from './abp-http-configuration.service';
  6. const apiHttpClient = axios.create({
  7.   baseURL: AppConsts.remoteServiceBaseUrl,
  8.   timeout: 300000,
  9. });
  10. // 请求拦截器
  11. apiHttpClient.interceptors.request.use(
  12.   (config: any) => {
  13.      // ....
  14.     return config;
  15.   },
  16.   (error: any) => {
  17.     return Promise.reject(error);
  18.   },
  19. );
  20. // 响应拦截器
  21. apiHttpClient.interceptors.response.use(
  22.   (response: AxiosResponse) => {
  23.     // 响应成功拦截器
  24.     if (response.data.__abp) {
  25.       response.data = response.data.result;
  26.     }
  27.     return response;
  28.   },
  29.   (error: any) => {
  30.     // 响应失败拦截器
  31.            //方法里存在异步,使用一个Promise包裹起来
  32.     return new Promise((resolve, reject) => {
  33.       // 关闭所有模态框
  34.       Modal.destroyAll();
  35.       const errorResponse = error.response;
  36.       const ajaxResponse = abpHttpConfiguration.getAbpAjaxResponseOrNull(error.response);
  37.       if (ajaxResponse != null) {
  38.         abpHttpConfiguration.handleAbpResponse(errorResponse, ajaxResponse);
  39.         reject(error);
  40.       } else {
  41.         if (errorResponse.status == 420) {
  42.           //abpHttpConfiguration中自己写的一个模态框弹窗,把响应数据传入其中
  43.           abpHttpConfiguration.needIntercept(errorResponse.data)
  44.             .toPromise()//Observable转Promise
  45.             .then((value) => {
  46.               if (value) {
  47.                 // resolve 原先的请求地址,重发请求
  48.                 resolve(apiHttpClient(errorResponse.config));
  49.               } else {
  50.                 reject(error);
  51.               }
  52.             });
  53.         } else {
  54.           abpHttpConfiguration.handleNonAbpErrorResponse(errorResponse);
  55.           reject(error);
  56.         }
  57.       }
  58.     });
  59.   },
  60. );
  61. export default apiHttpClient;
复制代码

  • 模态框弹窗,返回的bool类型
  1. //是否验证需求通过弹窗
  2.   needIntercept(error): Observable<Boolean> {
  3.     return new Observable<Boolean>((obs) => {
  4.       if (error != undefined && error.SignStatus != null && !error.SignStatus) {
  5.         //弹出模态框
  6.         this.modalCreate(error).subscribe(
  7.           (b) => {
  8.             obs.next(b);
  9.             obs.complete();
  10.           },
  11.           (error) => console.log(error, 123),
  12.           () => {
  13.             obs.next(false);
  14.             obs.complete();
  15.           },
  16.         );
  17.       } else {
  18.         obs.next(false);
  19.         obs.complete();
  20.       }
  21.     });
  22.   }
  23.   //电子签名弹窗
  24.   modalCreate(responseBody: any): Observable<Boolean> {
  25.     let sub;
  26.     if (!responseBody.IsAccountSign) {
  27.       //弹出模态框,指定的组件GESignNameComponent ,传入参数
  28.       sub = modalHelper.create(
  29.         GESignNameComponent,
  30.         {
  31.           relationId: responseBody.ModelSignNameId,
  32.           listEsignRequirementId: responseBody.ListSignRequirementId,
  33.         },
  34.       );
  35.     } else {
  36.       //弹出模态框,GESignNameAccountComponent ,传入参数
  37.       sub = modalHelper.create(
  38.         GESignNameAccountComponent,
  39.         {
  40.           relationId: responseBody.ModelSignNameId,
  41.           listEsignRequirementId: responseBody.ListSignRequirementId,
  42.         },
  43.       );
  44.     }
  45.     return sub;
  46.   }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

知者何南

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表