.NET中间件与VUE拦截器联合使用详情

 更新时间:2022年07月19日 11:40:46   作者:ke210  
这篇文章主要介绍了.NET中间件与VUE拦截器联合使用详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

前言:

工作中遇见的问题,边学边弄,记录一下Vue的UI库使用的是antvue 3.2.9版本的。

业务逻辑

特性:

//特性
    public class ModelEsignNameAttribute : Attribute
    {
        public ModelEsignNameAttribute(string nameProp, string id, string reversion = "", ModelESignType eSignType = ModelESignType.Modeling, string middleModelId = "")
        {

        }
    }

接口加上特性:

        /// <summary>
        ///  添加或者修改方法
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
		//特性上添加参数的地址
        [ModelEsignName("Bolg.BolgBaseEditDto.BolgName", "Document.Id", "Bolg.BolgRevision")]
        public async Task<Output> CreateOrUpdate(CreateOrUpdateBolgInput input)
        {
            var doc = await _XXXXManager.FindRdoById(input.Bolg.Id.Value);

            // 文档id为空,新增
            if (doc == null || !input.Bolg.BolgBaseId.HasValue)
            {
                return await this.Create(input.Bolg);
            }

            // 更新
            return await this.Update(input.Bolg);
        }

中间件代码:

namespace GCT.MedPro.Middleware
{
    public class ModelESignCheckMiddleware : IMiddleware
    {
		#region 依赖注入等内容
			....
        #endregion
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {

            if (await ShouldCheckESign(context))
            {
                // 不需要电子签名
                await next(context);
            }

        }
        /// <summary>
        /// 是否需要拦截
        /// </summary>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        private async Task<bool> ShouldCheckESign(HttpContext actionContext)
        {
            var whetherSignature = true;

            var request = actionContext.Request;//获取请求值
            var currentUser = actionContext.User.Identity.Name;
            var serviceAction = actionContext
                    .GetEndpoint()?
                    .Metadata
                    .GetMetadata<ControllerActionDescriptor>();
            if (serviceAction == null)
            {
                return whetherSignature;
            }
            //通过接口特性来筛选是否需要进行拦截
            var attrObj = serviceAction.MethodInfo.CustomAttributes
                .FirstOrDefault(x => x.AttributeType == typeof(ModelEsignNameAttribute));

            if (attrObj == null)
            {
                return whetherSignature;
            }
            
            string inputbody = default;
            actionContext.Request.EnableBuffering();
            
            //Post请求获取请求参数,转换JSON
            if (request.Method.ToLower().Equals("post"))
            {
                var requestReader = new StreamReader(actionContext.Request.Body);
                var body = await requestReader.ReadToEndAsync();
                inputbody = UpperFirst(body); //首字母大写    全局搜索可得下方有
            }
            else   //GET请求以及其他方式获取
            {
                var reqString = request.QueryString.Value.Remove(0, 1);
                string[] parts = reqString.Split("&");
                JObject json = new JObject();

                foreach (string part in parts)
                {
                    String[] keyVal = part.Split("=");
                    json.Add(keyVal[0], keyVal[1]);
                }
                inputbody = JsonConvert.SerializeObject(json);
                inputbody = UpperFirst(inputbody);
            }
            
            var inputObj = JObject.Parse(inputbody);//转换JObject
            
            
            #region 获取特性传入的参数,,总五位参数
			var actionName = serviceAction.ActionName;
            var namePath = attrObj.ConstructorArguments[0].Value.ToString();
            var idPath = attrObj.ConstructorArguments[1].Value.ToString();
            var revsionPath = attrObj.ConstructorArguments[2].Value.ToString();
            var typePath = (ModelESignType)attrObj.ConstructorArguments[3].Value;
            var middlePath = attrObj.ConstructorArguments[4].Value.ToString();
        	#endregion
            var middleModelId = GetValueName(inputObj, middlePath);//通过JObject获取对应值
            //接口控制器名称
            var typeName = serviceAction.ControllerTypeInfo.FullName;
            //重置请求Body指针  
            actionContext.Request.Body.Position = 0;
            //验证方法,自己写个,自已业务的处理验证
            var output = await CheckSign(middleModelId);
            
            if (!output.SignStatus)
            {
                actionContext.Request.EnableBuffering();
                Stream originalBody = actionContext.Response.Body;
                try
                {
                    using (var ms = new MemoryStream())
                    {
                        //修改响应状态麻420
                        actionContext.Response.Body = ms;
                        actionContext.Response.StatusCode = 420;
                        ms.Position = 0;
                        //写入数据
                        var responseBody = TextJosn.JsonSerializer.Serialize(output);
                        var memoryStream = new MemoryStream();
                       
                        var sw = new StreamWriter(memoryStream);
                         //自己编辑的实体写入响应体
                        sw.Write(responseBody);
                        sw.Flush();
		
                        //重置响应指针
                        memoryStream.Position = 0;
                        //复制到原body上
                        await memoryStream.CopyToAsync(originalBody);
                    }
                }
                finally
                {
                    actionContext.Response.Body = originalBody;
                    actionContext.Request.Body.Position = 0;
                }

                whetherSignature = false;
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(output.ErrorMessage))
                {
                    var serializerSettings = new JsonSerializerSettings
                    {
                        // 设置为驼峰命名
                        ContractResolver = new Newtonsoft.Json.Serialization
                            .CamelCasePropertyNamesContractResolver()
                    };
                    //错误友好提示,适配中间件中抛出错误,修改响应体
                    var exception = new UserFriendlyException(output.ErrorMessage);
                    actionContext.Response.StatusCode = 500;
                    actionContext.Response.ContentType = "application/json; charset=utf-8";
                    //写入
                    await actionContext.Response.WriteAsync(
                    JsonConvert.SerializeObject(
                        new AjaxResponse(
                            _errorInfoBuilder.BuildForException(exception),
                            true
                             ), serializerSettings
                         )
                    );
                    whetherSignature = false;
                }
            }

            return whetherSignature;
        }
		//取出json的Name值
        private string GetValueName(JObject inputObj, string path)
        {
            string result = null;
            if (!string.IsNullOrWhiteSpace(path))
            {
                result = inputObj.SelectToken(path).ToObject<string>();
            }
            return result;
        }
        /// <summary>
        /// Json字符串首字母转大写
        /// </summary>
        /// <param name="strJsonData">json字符串</param>
        /// <returns></returns>
        public static string UpperFirst(string strJsonData)
        {
            MatchCollection matchCollection = Regex.Matches(strJsonData, "\\\"[a-zA-Z0-9]+\\\"\\s*:");
            foreach (Match item in matchCollection)
            {
                string res = Regex.Replace(item.Value, @"\b[a-z]\w+", delegate (Match match)
                {
                    string val = match.ToString();
                    return char.ToUpper(val[0]) + val.Substring(1);
                });
                strJsonData = strJsonData.Replace(item.Value, res);
            }
            return strJsonData;
        }
    }
}

Vue拦截器,拦截失败的响应,状态码为420的,中间件修改的响应的状态码:

import { AppConsts } from '/@/abpPro/AppConsts';
import { abpService } from '/@/shared/abp';
import { Modal } from 'ant-design-vue';
import axios, { AxiosResponse } from 'axios';
import abpHttpConfiguration from './abp-http-configuration.service';
const apiHttpClient = axios.create({
  baseURL: AppConsts.remoteServiceBaseUrl,
  timeout: 300000,
});
// 请求拦截器
apiHttpClient.interceptors.request.use(
  (config: any) => {
     // ....
    return config;
  },
  (error: any) => {
    return Promise.reject(error);
  },
);
// 响应拦截器
apiHttpClient.interceptors.response.use(
  (response: AxiosResponse) => {
    // 响应成功拦截器
    if (response.data.__abp) {
      response.data = response.data.result;
    }
    return response;
  },
  (error: any) => {
    // 响应失败拦截器
   	//方法里存在异步,使用一个Promise包裹起来
    return new Promise((resolve, reject) => {
      // 关闭所有模态框
      Modal.destroyAll();
      const errorResponse = error.response;
      const ajaxResponse = abpHttpConfiguration.getAbpAjaxResponseOrNull(error.response);
      if (ajaxResponse != null) {
        abpHttpConfiguration.handleAbpResponse(errorResponse, ajaxResponse);
        reject(error);
      } else {
        if (errorResponse.status == 420) {
          //abpHttpConfiguration中自己写的一个模态框弹窗,把响应数据传入其中
          abpHttpConfiguration.needIntercept(errorResponse.data)
            .toPromise()//Observable转Promise
            .then((value) => {
              if (value) {
                // resolve 原先的请求地址,重发请求
                resolve(apiHttpClient(errorResponse.config));
              } else {
                reject(error);
              }
            });
        } else {
          abpHttpConfiguration.handleNonAbpErrorResponse(errorResponse);
          reject(error);
        }
      }
    });
  },
);
export default apiHttpClient;

模态框弹窗,返回的bool类型:

//是否验证需求通过弹窗
  needIntercept(error): Observable<Boolean> {
    return new Observable<Boolean>((obs) => {
      if (error != undefined && error.SignStatus != null && !error.SignStatus) {
        //弹出模态框
        this.modalCreate(error).subscribe(
          (b) => {
            obs.next(b);
            obs.complete();
          },
          (error) => console.log(error, 123),
          () => {
            obs.next(false);
            obs.complete();
          },
        );
      } else {
        obs.next(false);
        obs.complete();
      }
    });
  }
  //电子签名弹窗
  modalCreate(responseBody: any): Observable<Boolean> {
    let sub;
    if (!responseBody.IsAccountSign) {
      //弹出模态框,指定的组件GESignNameComponent ,传入参数
      sub = modalHelper.create(
        GESignNameComponent,
        {
          relationId: responseBody.ModelSignNameId,
          listEsignRequirementId: responseBody.ListSignRequirementId,
        },
      );
    } else {
      //弹出模态框,GESignNameAccountComponent ,传入参数
      sub = modalHelper.create(
        GESignNameAccountComponent,
        {
          relationId: responseBody.ModelSignNameId,
          listEsignRequirementId: responseBody.ListSignRequirementId,
        },
      );
    }
    return sub;
  }

到此这篇关于.NET中间件与VUE拦截器联合使用详情的文章就介绍到这了,更多相关.NET VUE拦截器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论