.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攔截器內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: