C# Azure函数处理SendGrid入站解析时shift_jis日文乱码问题
问题1:非UTF-8编码邮件对应Inbound Parse webhook中html/text字段的实际编码
SendGrid Inbound Parse 不会对邮件正文做转码处理,webhook采用multipart/form-data格式提交时,text、html字段直接携带邮件原始编码对应的原始字节,也就是你场景里的shift_jis编码字节。
乱码的核心原因是ASP.NET Core的默认表单解析逻辑固定使用UTF-8编码解码所有表单字段的字节,遇到shift_jis的无效UTF-8序列时会直接替换为Unicode替换字符�,你通过request.Form["text"]拿到的字符串已经是丢失原始信息的损坏数据,这也是你后续调用Encoding.Convert仍然得到乱码的原因——损坏发生在表单解析阶段,后续对已损坏字符串做任何转码操作都无法恢复原始内容。
问题2:正确读取shift_jis等非UTF-8编码正文的方法
核心原则是绕开默认的UTF-8表单解析逻辑,直接读取请求原始字节,按字段标注的字符集做解码,具体操作步骤如下:
- 首先在项目启动时注册额外代码页编码支持,.NET Core/.NET 5+ 默认不包含shift_jis等非Unicode编码的实现,需要先引入编码提供程序:
// 全局仅需执行一次,可放在Azure Functions的Startup配置或Program.cs中 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
- 不要直接访问
request.Form获取字段值,避免框架提前用UTF-8解码损坏内容。如果请求体已经被框架读取过,先调用request.EnableBuffering()并将request.Body.Position重置为0,再读取原始流。 - 自行解析
multipart/form-data格式的请求体,逐个读取表单区段,提取每个字段的原始字节和标注的字符集,再用对应编码将字节转为字符串。
最小实现代码参考:
// 从请求头解析multipart分隔符 var contentType = MediaTypeHeaderValue.Parse(req.ContentType); var boundary = contentType.Parameters .First(p => p.Name.Equals("boundary", StringComparison.OrdinalIgnoreCase)) .Value.Value.Trim('"'); // 初始化multipart读取器 var reader = new MultipartReader(boundary, req.Body); var fieldStore = new Dictionary<string, (string Charset, byte[] RawBytes)>(); MultipartSection section; while ((section = await reader.ReadNextSectionAsync()) != null) { if (!ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var disposition)) continue; if (!disposition.DispositionType.Equals("form-data", StringComparison.OrdinalIgnoreCase)) continue; if (string.IsNullOrEmpty(disposition.Name)) continue; // 提取字段名 var fieldName = disposition.Name.Value.Trim('"'); // 提取字段标注的字符集,未标注时默认使用UTF-8 var fieldCharset = section.ContentType != null ? MediaTypeHeaderValue.Parse(section.ContentType).Charset?.Value ?? "utf-8" : "utf-8"; // 读取字段原始字节,不做任何预解码 using var ms = new MemoryStream(); await section.Body.CopyToAsync(ms); fieldStore[fieldName] = (fieldCharset, ms.ToArray()); } // 按对应编码解码字段 var text = Encoding.GetEncoding(fieldStore["text"].Charset).GetString(fieldStore["text"].RawBytes); var html = Encoding.GetEncoding(fieldStore["html"].Charset).GetString(fieldStore["html"].RawBytes); var subject = Encoding.UTF8.GetString(fieldStore["subject"].RawBytes); // 邮件头固定为UTF-8
- 注意:不要尝试用
Encoding.UTF8.GetBytes(乱码字符串)再转shift_jis的方式修复乱码,这种方式仅适用于单字节编码错配的场景,UTF-8解码时已经将无法识别的字节替换为�,原始字节信息永久丢失,无法通过转码恢复。
内容的提问来源于stack exchange,提问作者user19540551
相关产品推荐
相关产品推荐

