Nginx反向代理DigitalOcean Spaces传Unicode文件名报Bad Request修复方案
问题背景
当前使用的Nginx location配置如下:
location ~^/media/(.+)/(.+)$ { error_log /home/user/Server/nginx/logs/error.log; access_log /home/user/Server/nginx/logs/access.log; proxy_pass https://bucketname.sgp1.digitaloceanspaces.com/$1/$2; }
故障表现:
- 正则第二个捕获组匹配纯英文字符组成的文件名时,代理转发功能正常
- 第二个捕获组匹配印地语等Unicode字符文件名时,服务返回
400 Bad Request错误 - 访问日志中可见对应Unicode文件名请求的上游响应状态码为400
故障根因
Nginx在正则location中提取捕获组内容时,$1/$2变量存储的是URL解码后的原始Unicode字符串。手动将解码后的变量直接拼接到proxy_pass的上游请求路径时,Nginx不会自动对非ASCII字符做百分号编码,会直接把原始Unicode字节放到HTTP请求行中发送给DigitalOcean Spaces。
按照HTTP协议规范,URL路径中的非ASCII字符必须经过百分号编码才合法,DigitalOcean Spaces作为S3兼容的对象存储服务,收到包含未编码非ASCII字符的非法请求时,会直接返回400错误。
修复方案
移除手动拼接捕获组的逻辑,改用Nginx原生rewrite逻辑保留原始URL编码,修改后的配置如下:
location ~ ^/media/ { error_log /home/user/Server/nginx/logs/error.log; access_log /home/user/Server/nginx/logs/access.log; # 剥离/media/前缀,完整保留原始路径的URL编码格式 rewrite ^/media/(.*)$ /$1 break; # 直接转发到上游根域名,Nginx会自动将符合编码规范的路径发送给上游服务 proxy_pass https://bucketname.sgp1.digitaloceanspaces.com; }
配置修改完成后依次执行以下命令验证并生效:
- 校验配置语法正确性:
nginx -t - 重载Nginx配置使规则生效:
nginx -s reload
该方案无需安装任何第三方Nginx模块,兼容性比原正则捕获组写法更强,支持/media路径下任意层级的路径转发,无论是英文文件名还是多语言Unicode文件名,都可以正常转发到Spaces服务端,不会再触发400错误。
内容的提问来源于stack exchange,提问作者Future King
相关产品推荐
相关产品推荐

