随笔背景:因为项目中有个简单的功能是需要实现中文简体到繁体的切换,数据库中存储的源数据都是中文简体的,为了省事就想着通过HttpHeader的方式来控制Api返回对应的繁体数据。
实现方式:通过Asp.Net Core 中的中间件来拦截HttpResponse,然后通过转换字符编码来实现中文繁体切换。
实现代码如下:
HttpContextMiddleware 中间件
public class HttpContextMiddleware { private readonly RequestDelegate _next; public HttpContextMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { var originalBodyStream = context.Response.Body; using (var responseBody = new MemoryStream()) { context.Response.Body = responseBody; await _next(context); var result = await FormatResponse(context.Response); if (context.Request.Headers.Keys.Contains(Constants.HttpHeaderLanguage)) { var lang = context.Request.Headers.GetCommaSeparatedValues(Constants.HttpHeaderLanguage).GetValue(0).ToString(); if (lang == "zh-tw") { var traditionresult = ConvertHelper.ToTraditional(result); byte[] array = Encoding.UTF8.GetBytes(traditionresult); MemoryStream stream = new MemoryStream(array); try { await stream.CopyToAsync(originalBodyStream); } catch (Exception ex) { throw ex; } } else { try { await responseBody.CopyToAsync(originalBodyStream); } catch (Exception ex) { throw ex; } } } else { await responseBody.CopyToAsync(originalBodyStream); } } } private async Task<string> FormatResponse(HttpResponse response) { response.Body.Seek(0, SeekOrigin.Begin); var text = await new StreamReader(response.Body).ReadToEndAsync(); response.Body.Seek(0, SeekOrigin.Begin); return $"{text}"; } }
Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseDefaultFiles(); app.UseAuthentication(); app.UseStaticFiles(); //在Mvc之前注入到管道中 app.UseMiddleware<HttpContextMiddleware>(); app.UseMvc(); }
ConvertHelper 中文简体繁体转换工具类
public static class ConvertHelper { private const int LOCALE_SYSTEM_DEFAULT = 0x0800; private const int LCMAP_SIMPLIFIED_CHINESE = 0x02000000; private const int LCMAP_TRADITIONAL_CHINESE = 0x04000000; [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)] private static extern int LCMapString(int Locale, int dwMapFlags, string lpSrcStr, int cchSrc, [Out] string lpDestStr, int cchDest); /// <summary> /// 将字符转换成简体中文 /// </summary> /// <param name="source">输入要转换的字符串</param> /// <returns>转换完成后的字符串</returns> public static string ToSimplified(string source) { String target = new String(' ', source.Length); int ret = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_SIMPLIFIED_CHINESE, source, source.Length, target, source.Length); return target; } /// <summary> /// 将字符转换为繁体中文 /// </summary> /// <param name="source">输入要转换的字符串</param> /// <returns>转换完成后的字符串</returns> public static string ToTraditional(string source) { String target = new String(' ', source.Length); int ret = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_TRADITIONAL_CHINESE, source, source.Length, target, source.Length); return target; } }
以上源代码就是所有关键代码了,中间件注入以后,不用再在action里或controller里单独拦截,经测试,会拦截所有api的响应结果。这里有个插曲是我之前尝试过使用ResultFilter来拦截,但没法做到在响应后拦截响应结果。不知出于什么原因,最后我放弃了Filter的方式,选择了这种中间件的拦截方式。
本文参考如下:
https://elanderson.net/2017/02/log-requests-and-responses-in-asp-net-core/
本文如有不对的地方,欢迎指正!愿与君共勉。
最后,感谢您的阅读!