S3的中文编码问题及修复方案

S3的中文编码问题及修复方案

原创 小包子大 网易游戏运维平台 2019-08-10

 

小包子大

06 年加入网易游戏,先后负责过多个端游/手游产品的运维工作;多年运维生涯,历经数次运维技术变革;本人关注广泛,Web/CDN,自动化,分布式等,欢迎来侃;作为十多年运维老兵, 平日写些别人看着晦涩的东西,擅长手术刀式的运维杂症分析。

二个月前,游戏的流媒体站点从物理机迁移到了 S3,迁移过程中发生了一些小插曲,今天分享下其中的 S3 中文文件名的编码问题及解决方法。

这里指的中文,是指文件名带中文,而不是文件内容。

中文主要有 2 种编码,UTF-8 与 GBK,服务器环境大都是 UTF-8 编码,而 Windows 系统则采用 GBK。

PS. 本文档不区分字符集与字符编码,二者在这里可以混用。

一、中文文件名与S3上传的编码问题

当上传到 S3 的文件名带有中文时,上传时的编码环境很重要。

文件名采用什么编码,就需要在相应的编码环境上传,否则无法上传

比如,一个文件名采用 GBK 编码的文件,在 GBK 编码环境下,正常上传


而同一个文件,切换到 UTF-8 环境下,上传报错


上面这个编码要求还算说得过去,但当以目录为单位上传到 S3 时,异常编码的文件,会被 “静默地“ 忽略掉!
即当你想同步整个目录到 S3 时,实际只是同步了名字编码没有问题的文件,请注意这个坑。

二、S3 Website的中文文件名问题

上传的编码问题,还好解决,下行的问题,就比较麻烦了,原因是 S3 只支持 UTF-8!

所有上传到 S3 的文件,文件名都将被强制为 UTF-8 编码


上面的测试中,我们在 GBK 编码环境下,上传了一个文件名采用 GBK 编码的文件,现在来访问它。

当使用 GBK 编码时,返回 400,注意,是 400!

切到 UTF-8 编码,则可以正常访问,即我们上传的 GBK 编码的中文文件名,被强制转为了 UTF-8

三、S3强制使用UTF-8编码的影响

大家知道,目前的端游,几乎都是基于 Windows 平台,而 Windows 使用的是 GBK 编码,因此,这些端游的客户端采用 GBK 编码,这些客户端生成的文件,也是 GBK 编码的。我们所熟知的西游系列的端游,会产生大量的战斗录像,这些战斗录像,有一些是使用中文文件名,当这些录像文件,上传到 S3 后,客户端/播放器 再尝试以 GBK 编码去请求录像时,就会产生 400 错误。

四、当前的文件访问路径

这里只说下 S3 Proxy 的用途

  • 实现基于 S3 Bucket 子目录的虚拟主机

  • 为后续扩容的多个 Buckets 提供统一的入口

五、如何修复这个编码问题

大致的思路是,服务端作适配,将 Client 的 GBK 编码的请求,在转发到 S3 Bucket 前,将请求的 URI 转为 UTF-8 编码,

其它诸如在客户端作调整的方案,暂不考虑!(对业务的少侵入/零侵入原则)

目前,这个 URI 转编码,理论上,在 LBC,S3 Proxy 或 S3 GW 上面都可以做,考虑到在通用业务上作调整的风险太大,故这个转编码的工作,放在业务专用的 S3 Proxy 上。

URI 转编码考虑的主要因素:

  • 中文文件名可以采用 GBK 或 UTF-8 编码,Client 访问这些文件时,可能是 UTF-8 或 GBK 编码

  • 如果用户请求的 URI 属于单字节编码的字符集,无需调整编码 (GBK/UTF-8 都可以与之兼容)

  • 如果用户是使用 GBK 编码,那 URI 需要先转码为 UTF-8,再转发到 S3

  • 如果用户是使用 UTF-8 编码,无需调整 URI 编码,直接转发到 S3

看看nginx的URI转编码方案

# nginx + lua/iconv (openresty)
rewrite_by_lua_block {
    local iconv = require 'resty.iconv'
    local request_uri = ngx.var.request_uri
    local handler, errmsg = iconv:new("utf-8", "gbk")
    if not handler then
        return ngx.say(errmsg)
    end
    local request_uri_utf8, words = handler:convert(request_uri)
    if not request_uri_utf8 then
        return ngx.say(words)
    end
    ngx.req.set_uri(request_uri_utf8)
}

上述功能,也可以使用 nginx 第三方 iconv 扩展来做;

但主要的问题是,Nginx/Openresty 如何原生地获取到 Client 请求时使用的编码,上述方案都是假设 Client 固定使用 GBK。

当前无法判断Client请求的编码,故采取新的思路

强制(盲转)转码,如果转码异常,请求转到 S3 后将返回 403,我们将这个 403 捕捉,再进行一次正常合理的转编码, 而这次转编码后,S3 将正常返回。

以下是主要的 nginx 配置代码

#下面定义了2个Server,请注意,2个Server的Upstream,是同一个,指向同一个S3 !

#定义 8003 服务器,使用S3作为Upstream
server {
    listen 8003 default_server;
    server_name wahaha-wahaha.s3.nie.netease.com;
    location / {
        #这里进行URI编码盲转,强制认为Client编码为UTF-8,并转码为UTF-8 -_-
        #当Client编码为非UTF-8时,转编码后,Upstream将返回403,这个403将被捕捉!
        proxy_pass  http://wahaha-wahaha.s3.nie.netease.com;
    }
}

#定义 8004 服务器,使用S3作为Upstream
server {
    listen 8004 default_server;
    server_name wahaha-wahaha.s3.nie.netease.com;
    location / {
        #这里进行URI编码盲转,强制认为Client编码为GBK,并转码为UTF-8 -_-
        #当Client编码为非GBK时,转编码后,Upstream将返回403,这个403将被捕捉!
        proxy_pass  http://wahaha-wahaha.s3.nie.netease.com;;
    }
} 

# 注意:S3没有404的概念,原本当编码异常时,S3会返回400(不可捕捉), 强制转编码后,S3返回403(可捕捉)


# 再定义一个Upstream,引用上述8003,8004服务器
upstream v.nie {
    server 127.0.0.1:8003; #绝大多数情况下,URI都是单字节编码的字符集,所以将UTF-8设置为默认Client编码
    server 127.0.0.1:8004 backup; #少数文件名采用GBK编码,故作为从站
}

# S3 Proxy入口配置
server {
    listen 80;
    server_name  wahaha.wahaha.netease.com;
    #以2个RTT为代价,实现编码异常时的Failover(捕捉403)
    proxy_next_upstream http_403;
    location / {
        #回源到8003,8004, 并最终回源到S3 Bucket
        proxy_pass       http://v.nie$uri;
    }
}

验证,URI 转码后,符合需求!

GBK 编码下,正常请求

UTF 编码下,正常请求

小结

这个方案,同时支持采用 GBK 与 UTF-8 编码访问 S3 Website 上的同一个文件!

往期精彩

NEW

通用实时日志分类统计实践

从清档需求谈谈 Redis 二级索引的使用

Swap 与 Swappiness

网易游戏海外 AWS 动态伸缩实践

深入理解实时计算中的 Watermark

S3C44B0 ARM7开发板上进行开发和调试时,串口通信的稳定性和准确性至关重要。当遇到通过H-JTAG调试工具进行串口通信时出现乱码问题,我们需要从多个角度来分析和解决这一问题。 参考资源链接:[ADS1.2-44B0开发调试指南:安装与仿真步骤详解](https://wenku.csdn.net/doc/27s4gbxhk6) 首先,需要确保H-JTAG工具正确安装,并且在ADS环境中正确配置。H-JTAG安装步骤包括将HJTAG.DLL文件复制到指定路径,并在ADS中配置调试器,确保选择了正确的H-JTAG动态链接库。 其次,在软件层面,检查`printf`函数的使用是否存在问题。通常,乱码的原因可能是因为数据在传输或处理过程中溢出,导致输出内容不正确。解决方案可能包括增加数据缓冲区的大小,或者在数据输出前进行适当的格式化处理。 如果软件层面检查无误,接下来需要检查硬件连接是否稳固,包括串口线和连接器是否正确连接,没有出现接触不良的情况。同时,检查开发板的串口电路是否工作正常,可以尝试更换或修复损坏的晶振和电容等元件。 最后,进行实际的硬件故障排查。通过逐步测试每一条数据线,观察数据线上的信号是否符合预期,可以使用逻辑分析仪或示波器等工具来辅助检测。这种方法不仅可以帮助确定串口通信是否稳定,还能帮助发现硬件故障的可能位置。 通过以上步骤,可以系统地排查和解决S3C44B0 ARM7开发板在使用H-JTAG进行串口通信时遇到的乱码问题。对于更深入的理解和掌握,推荐阅读《ADS1.2-44B0开发调试指南:安装与仿真步骤详解》,该资源提供了详细的硬件与软件问题诊断和解决方法,将帮助开发人员更有效地定位和解决问题。 参考资源链接:[ADS1.2-44B0开发调试指南:安装与仿真步骤详解](https://wenku.csdn.net/doc/27s4gbxhk6)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值