You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 11:36:21