InvenTree开源库存管理系统:如何为中小企业打造高效物料追踪解决方案
2026/7/17 12:59:19
本文基于一个实际的项目需求,做下记录并分享。
在 Web 开发中,通过 Nginx 代理转发下载文件是一个常见需求。特别是当目标文件包含中文文件名时,经常会遇到两个棘手的问题:
changeprotocol)。本文将重点介绍如何配置 Nginx,在代理转发场景下,完美解决中文文件下载及文件名保留的问题。
中国.png)。中国.png)。访问地址示例:http://10.86.37.169:9302/changeprotocol?changeprotocol=http://10.86.37.169:9301/中国.png
在代理转发过程中,Nginx 默认只是透传数据流,不会自动处理Content-Disposition头。
/changeprotocol),而不是真实文件的路径,因此默认使用接口名作为文件名。%E4%B8%AD...),直接转发可能导致源服务器无法识别路径,或者浏览器下载后文件名乱码。为了解决上述问题,我们需要在代理服务器的 Nginx 配置中进行干预:
add_header强制设置Content-Disposition,明确告诉浏览器“这是一个附件,请使用提取出的中文文件名保存”。以下是完整的nginx.conf配置片段:
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # ---------------------------------------------------- # 1. 文件源服务器 (模拟后端存储) # ---------------------------------------------------- server { listen 9301; server_name 10.86.37.169; charset utf-8; # 关键:设置字符集,防止中文文件名读取失败 location / { # 确保此目录下存在 "中国.png" 等文件 root D:/nginx-1.17.1/www; index index.html index.htm; } } # ---------------------------------------------------- # 2. 代理下载服务器 # ---------------------------------------------------- server { listen 9302; server_name 10.86.37.169; # 精确匹配 /changeprotocol 路径 location = /changeprotocol { # 必须指定 resolver 以便解析域名(如果是 IP 可忽略,但建议加上) resolver 180.76.76.76; # 1. 从 query 参数中获取真实 URL set $stream_url $arg_changeprotocol; # 安全检查:如果参数为空,返回 400 if ($stream_url = "") { return 400; } # 2. 使用正则提取文件名(支持中文) # 逻辑:匹配最后一个 / 之后,且不包含 ? 的字符序列 if ($stream_url ~* ".*/([^/?]+)$") { set $filename $1; # 3. 关键步骤:添加 Content-Disposition 头 # 强制浏览器使用提取出的原始文件名(包含中文)进行下载 add_header Content-Disposition 'attachment; filename="$filename"'; } # 清除可能影响代理的头信息 proxy_set_header Cookie ""; proxy_set_header Host ""; # 执行代理 proxy_pass $stream_url; # 设置字符集和超时 charset utf-8; proxy_connect_timeout 60s; proxy_read_timeout 600s; proxy_send_timeout 600s; } } }set $stream_url $arg_changeprotocol;
Nginx 自动将 URL 参数?changeprotocol=xxx映射为变量$arg_changeprotocol。
正则提取文件名:
if ($stream_url ~* ".*/([^/?]+)$")~*: 不区分大小写匹配。.*/: 匹配最后一个斜杠之前的所有内容。([^/?]+): 捕获组,匹配斜杠之后、问号(如果有参数)之前的内容。这就是我们需要的文件名。Content-Disposition:
add_header Content-Disposition 'attachment; filename="$filename"';这是告诉浏览器“这是一个附件,请保存为$filename”的标准 HTTP 头。
常见错误排查 (CreateFile failed):
如果在日志中看到CreateFile() ... failed (2: The system cannot find the file specified),通常是因为:
root路径下确实没有该文件。%E4%B8%AD%E5%9B%BD.png),而文件系统是中文的。确保 Nginx 配置了charset utf-8;,并且文件确实存在于磁盘上。通过以上配置,即可完美解决 Nginx 代理下载时的中文文件名保留问题。