Python CGI脚本实现文件下载后文件显示0字节问题求助
问题根因排查与修复方案
核心错误点
- 文件路径错误:原代码中
with open打开的是当前工作目录下的filename,而非存放在cgi-bin/tmp目录下的目标文件,读取不到有效内容导致输出为空 - 输出方式错误:使用
print函数输出二进制文件内容,会自动追加换行符、触发编码转换,破坏文件结构,甚至直接输出空内容 - 冗余无效代码:原代码中打开
fullpath文件后从未使用也未关闭,属于无效逻辑 - HTML逻辑冲突:同时设置了表单提交逻辑和a标签直接下载逻辑,两者互斥,a标签跳转不会触发CGI脚本执行,如果tmp目录不可公开访问会直接返回404或空内容
- 缺少参数校验与文件存在性判断:未校验参数是否存在、文件是否可读,遇到异常情况直接输出空内容
修复后的代码
1. download_file.py 修正版
import cgi, os, sys form = cgi.FieldStorage() # 读取文件名参数,异常兜底 filename = form.getfirst('fname', '') if not filename: print("Content-Type: text/html; charset=utf-8") print("") print("参数错误:未指定文件名") exit() # 拼接正确的目标文件路径 file_path = os.path.join('cgi-bin', 'tmp', filename) # 校验文件存在性 if not os.path.exists(file_path) or not os.path.isfile(file_path): print("Content-Type: text/html; charset=utf-8") print("") print("错误:请求的文件不存在") exit() # 输出标准下载HTTP头 print('Content-Type: application/octet-stream') print(f'Content-Disposition: attachment; filename="{filename}"') print(f'Content-Length: {os.path.getsize(file_path)}') print("") # 刷新缓冲区确保HTTP头优先输出 sys.stdout.flush() # 直接输出二进制文件流 with open(file_path, 'rb') as f: sys.stdout.buffer.write(f.read())
2. HTML部分修正(走CGI下载逻辑)
移除冲突的a标签,改用表单提交触发CGI下载:
html += """ <form action = "download_file.py" method = "get" class='file'> <h3>%s</h3> <h4>File name: %s</h4> <input type='hidden' value="%s" name='fname'> <button type="submit" class='btn btn-info'>Download File</button> </form> """ % (str(i+1), str(files[i]['name']), str(files[i]['name']))
额外注意事项
- CGI脚本需要有读取
cgi-bin/tmp目录下文件的权限,目录权限设置为755、文件权限设置为644即可 - 如果你选择直接用a标签静态下载,需要将
tmp目录移动到web服务器的静态资源根目录,不要放在cgi-bin目录下,避免web服务器拦截静态资源请求
内容的提问来源于stack exchange,提问作者Coding Explorer
相关产品推荐
相关产品推荐

