Django结合Apache用xsendfile提供非ASCII文件名文件返回404如何解决
问题原因
- 路径拼接逻辑错误:
file.file.url是对外访问的URL路径(非ASCII字符会被URL编码转换为%xx格式),不能直接和本地路径settings.BASE_DIR拼接得到本地文件绝对路径,拼接后的路径包含URL编码字符,Apache无法找到对应文件返回404;ASCII字符URL编码后和原字符一致,所以不受影响。 - 编码不匹配:mod_xsendfile要求
X-Sendfile头传入的路径编码必须和服务器文件系统编码完全一致,若smart_str未指定对应编码,非ASCII字符会出现乱码,导致Apache无法定位文件。 - 配置项大小写错误:你给出的Apache配置中
XsendFilePath正确写法为首字母全大写的XSendFilePath,部分版本的mod_xsendfile对配置项大小写敏感,会导致权限校验不通过,非ASCII文件会在该环节被拦截返回404。
修复方案
1. 修正Django端代码
不要用URL拼接本地路径,直接用FileField的path属性获取本地原生绝对路径,同时指定smart_str编码和服务器文件系统编码匹配(Linux默认是utf-8,Windows默认是gbk):
def media_xsendfile_pdf(request): file = Media.objects.last() response = HttpResponse() response['Content-Type'] = 'application/pdf' # 直接用path属性获取本地原生路径,无需手动拼接 file_path = file.file.path # Linux环境指定encoding为utf-8,Windows环境替换为gbk response['X-Sendfile'] = smart_str(file_path, encoding='utf-8') # 可选:添加该头避免用户下载文件时文件名显示乱码 from django.utils.http import urlquote response['Content-Disposition'] = f"attachment; filename*=UTF-8''{urlquote(file.file.name)}" return response
2. 修正Apache配置
修正配置项大小写,Apache 2.4及以上版本可将AllowEncodedSlashes设置为NoDecode避免Apache自动解码路径导致的乱码:
AllowEncodedSlashes NoDecode XSendFile On # 修正配置项大小写 XSendFilePath /path-to-the-protected-resource
内容的提问来源于stack exchange,提问作者Gopinath
相关产品推荐
相关产品推荐

