.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!
推薦閱讀:
- C#通過JObject解析json對象
- c#添加Newtonsoft.Json包的操作
- C#中對象與JSON字符串互相轉換的三種方式
- c# 使用Json.NET實現json序列化
- C# 獲取動態key的json對象的值案例