我正在更新一个Angular web应用程序,以播放从AWS S3存储桶中检索到的任何语音音频文件。S3存储桶中的许多文件具有(将具有)多字节unicode文件名(因为应用程序将支持全局用户)。AWS (S3)以一种我无法在浏览器中轻松复制的方式对文件名进行编码。应用后端Lambda函数发送要检索的音频文件的文件名,然后Angular应用实例化一个HTMLAudioElement
,它向S3发送一个HTTP GET请求。
。文件名与Windows上一样(上传到S3之前):Godzilla [Blue Öyster Cult] instrumental #12.wav
B。使用S3控制台摄取的文件名:Godzilla %5BBlue %C3%96yster Cult%5D instrumental %2312.wav
C。文件名见S3控制台(下载链接):Godzilla+%5BBlue+%C3%96yster+Cult%5D+instrumental+%2312.wav
D。从应用程序后端Lambda(与A相同)返回的文件名:Godzilla [Blue Öyster Cult] instrumental #12.wav
E。HTTP GET浏览器audio.load()
文件名:Godzilla+[Blue+O%CC%88yster+Cult]+instrumental+%2312.wav
注:D &E(上图)是通过浏览器网络开发工具
确定的文件从Windows通过S3控制台上传到S3。保存在后端RDS数据库中的文件名与Windows文件名匹配。因为Lambda正在从RDS数据库中检索文件名,所以Lambda会将Windows文件名返回给浏览器上的Angular UI。浏览器audio.load()
正在"不正确地"转换多字节Ö
。访问S3上的文件(浏览器:O%CC%88yster
(UTF-8 combined DIAERESIS) vs. S3:%C3%96yster
)。看起来浏览器专注于转换重音,而不是像S3所做的那样转换多字节字符。
不允许剥离多字节字符以支持ASCII字符集。我正在寻找一种方法(没有手动编码映射的每一个可能的多字节字符转换)(和理想的没有新的依赖)来"说服";浏览器的行为方式与S3相同…我想这个问题可以归结为:S3在文件名中转换多字节字符的逻辑是什么?谁能提供实现这一目标的方法?
注意:Angular应用已经有了正确处理典型S3特殊字符情况的逻辑。这个问题只针对国际字符集。
下面的方法使用normalize('NFC')
将每个Unicode字符转换为其规范分解形式,使用encodeURIComponent()
将UTF-8字符编码应用于整个URL,而不改变/
和:
字符,同时将space
字符更改为+
字符。源url是split()
,使用/
:
space
作为分隔符。/
:
space
作为分隔符包含在split()
的输出中,非/
:
space
分隔符的URL段将应用normalize('NFC')
和encodeURIComponent()
。
const splits = '[/: ]';
const splitter = new RegExp(`(?=${splits})|(?<=${splits})`, 'g');
export function s3Url(url: string): string {
return url.split(splitter).reduce((s3Url: string, segment: string) => s3Url + (' ' === segment ? '+' : '/' === segment || ':' === segment ? segment : encodeURIComponent(segment.normalize('NFC'))), '');
}