当我在 Django 中使用 StreamingHttpResponse 时下载无法完成
Download can't finish when I use StreamingHttpResponse in Django
我在 Google 云 运行 上使用 Django。自从我更新 docker 图片后,下载文件页面就无法正常工作。下载文件页面程序如下
def file_iterator(file, chunk_size=512):
with open(file, 'rb') as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
def download_view(request, format, pk):
user = get_user(request)
sentence = Sentence.objects.get(pk=pk)
if not default_storage.exists(sentence.file.name):
logger.warning(f'This file has been deleted pk: {pk} user: {user} file_name:{sentence.file.name}')
raise Http404()
file_name = f'{user.pk}{sentence.pk}.{format}'
file_path = sentence.file.name
if format == 'mp3':
with open(file_path,'wb') as f:
f.write(sentence.file.read())
elif format == 'wav':
file_path = AudioSplitter().mp3_to_wav(sentence)
else:
return HttpResponse('format error')
response = StreamingHttpResponse(file_iterator(file_path))
response['Content-Type'] = 'audio/mpeg' if format == 'mp3' else 'audio/wav'
response['Content-Disposition'] = f'attachment;filename="{file_name}"'
return response
Google云运行有下载文件限制。所以这个程序使用了 StreamingHttpResponse。它是 return 分块文件数据。当我从这个视图下载文件时,下载文件堆积在 200 ~ 224KB 左右。
这个问题发生在2021年8月17日,我当天构建了3个镜像。
- 2021/08/17 10:24
- 2021/08/17 15:54
- 2021/08/17 20:58
第一个容器可以下载文件。但是第二个和第三个容器无法从视图中下载文件。而且所有构建的容器都无法在第一个容器之后下载文件。
第一个容器和第二个容器有什么区别?
我在 admin.py
中更改了一行它只是添加了 list_display_links = None
。
我检查了 python 模块版本和 python 版本。然而,它是一样的。
当我运行docker images
的时候,发现图片大小不一样
REPOSITOR TAG IMAGE ID CREATED SIZE
gcr.io/***/*** 8f6ae66 62d086d8f30c 7 weeks ago 2.07GB <-- 1st
gcr.io/***/*** bdf4a43 f67948780215 7 weeks ago 2.39GB <-- 2nd
第一个容器是 2.07GB,第二个容器是 2.39GB。我的 docker 文件正在使用 FROM python:3.9
。 8 月 17 日 python3.9 图片有更新吗??
我用第一张图片构建了相同的代码。当然,这个图像有下载页面问题,容器大小为 2.28GB。它比第一张图片大。 Python 模块有一些差异,python 版本已更新至 python 3.9.7.
我认为这个问题来自 python 的 docker 图片。我该如何解决这个问题?
更新
- 我把图片改成了
python: 3.8
。问题已复现
- 下载堆叠时发现这个错误。
uwsgi_response_write_body_do() TIMEOUT !!!
环境
第一张和第二张图片环境。
- 版本:nginx/1.14.2
- uWSGI==2.0.19.1
# nginx-app.conf
# the upstream component nginx needs to connect to
upstream django {
server unix:/code/app.sock; # for a file socket
# server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on, default_server indicates that this server block
# is the block to use if no blocks match the server_name
listen 8080;
# the domain name it will serve for
server_name xxx.com; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 10M; # adjust to taste
# set timeout
uwsgi_read_timeout 900;
proxy_read_timeout 900;
# Django media
location /media {
alias /code/app/media; # your Django project's media files - amend as required
}
location /static {
alias /code/app/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /code/uwsgi_params; # the uwsgi_params file you installed
}
}
[uwsgi]
# this config will be loaded if nothing specific is specified
# load base config from below
ini = :base
# %d is the dir this configuration file is in
socket = %dapp.sock
master = true
processes = 4
max-requests = 1000 ; Restart workers after this many requests
max-worker-lifetime = 3600 ; Restart workers after this many seconds
reload-on-rss = 512 ; Restart workers after this much resident memory
worker-reload-mercy = 60 ; How long to wait before forcefully killing workers
我解决了这个问题。我认为它是由这个错误引起的。
uwsgi_response_write_body_do() TIMEOUT !!!
我添加睡眠并更改块大小。
# change chunk size from 512 byte to 1 MB, because it sleep 0.1 sec each loop.
def file_iterator(file, chunk_size=1024 * 1024):
with open(file, 'rb') as f:
while True:
time.sleep(0.1) # <-- add sleep
c = f.read(chunk_size)
if c:
yield c
else:
break
P.S。我试过了this solution。但是对我没有影响。
更新
当我检查自己下载的时候。它工作正常。但是请求延迟非常慢。大约15~18分钟。当我 运行 第一张图片时,大约是 0.2 ~ 0.3 秒。并且 Charged 容器实例时间增加了 5 倍。
1 小时
1 天
我觉得这个解决方案是急救。我钻了一些答案真正的解决方案。
更新 2021/11/02
我找到了真正的解决方案! uWSGI 套接字连接有一些问题。我改变了端口连接。现在我的申请 return 结果非常正常。
注意:这是正常的uWSGI PORT连接设置。
我在 Google 云 运行 上使用 Django。自从我更新 docker 图片后,下载文件页面就无法正常工作。下载文件页面程序如下
def file_iterator(file, chunk_size=512):
with open(file, 'rb') as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
def download_view(request, format, pk):
user = get_user(request)
sentence = Sentence.objects.get(pk=pk)
if not default_storage.exists(sentence.file.name):
logger.warning(f'This file has been deleted pk: {pk} user: {user} file_name:{sentence.file.name}')
raise Http404()
file_name = f'{user.pk}{sentence.pk}.{format}'
file_path = sentence.file.name
if format == 'mp3':
with open(file_path,'wb') as f:
f.write(sentence.file.read())
elif format == 'wav':
file_path = AudioSplitter().mp3_to_wav(sentence)
else:
return HttpResponse('format error')
response = StreamingHttpResponse(file_iterator(file_path))
response['Content-Type'] = 'audio/mpeg' if format == 'mp3' else 'audio/wav'
response['Content-Disposition'] = f'attachment;filename="{file_name}"'
return response
Google云运行有下载文件限制。所以这个程序使用了 StreamingHttpResponse。它是 return 分块文件数据。当我从这个视图下载文件时,下载文件堆积在 200 ~ 224KB 左右。
这个问题发生在2021年8月17日,我当天构建了3个镜像。
- 2021/08/17 10:24
- 2021/08/17 15:54
- 2021/08/17 20:58
第一个容器可以下载文件。但是第二个和第三个容器无法从视图中下载文件。而且所有构建的容器都无法在第一个容器之后下载文件。
第一个容器和第二个容器有什么区别?
我在 admin.py
中更改了一行它只是添加了 list_display_links = None
。
我检查了 python 模块版本和 python 版本。然而,它是一样的。
当我运行docker images
的时候,发现图片大小不一样
REPOSITOR TAG IMAGE ID CREATED SIZE
gcr.io/***/*** 8f6ae66 62d086d8f30c 7 weeks ago 2.07GB <-- 1st
gcr.io/***/*** bdf4a43 f67948780215 7 weeks ago 2.39GB <-- 2nd
第一个容器是 2.07GB,第二个容器是 2.39GB。我的 docker 文件正在使用 FROM python:3.9
。 8 月 17 日 python3.9 图片有更新吗??
我用第一张图片构建了相同的代码。当然,这个图像有下载页面问题,容器大小为 2.28GB。它比第一张图片大。 Python 模块有一些差异,python 版本已更新至 python 3.9.7.
我认为这个问题来自 python 的 docker 图片。我该如何解决这个问题?
更新
- 我把图片改成了
python: 3.8
。问题已复现 - 下载堆叠时发现这个错误。
uwsgi_response_write_body_do() TIMEOUT !!!
环境
第一张和第二张图片环境。
- 版本:nginx/1.14.2
- uWSGI==2.0.19.1
# nginx-app.conf
# the upstream component nginx needs to connect to
upstream django {
server unix:/code/app.sock; # for a file socket
# server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on, default_server indicates that this server block
# is the block to use if no blocks match the server_name
listen 8080;
# the domain name it will serve for
server_name xxx.com; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 10M; # adjust to taste
# set timeout
uwsgi_read_timeout 900;
proxy_read_timeout 900;
# Django media
location /media {
alias /code/app/media; # your Django project's media files - amend as required
}
location /static {
alias /code/app/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /code/uwsgi_params; # the uwsgi_params file you installed
}
}
[uwsgi]
# this config will be loaded if nothing specific is specified
# load base config from below
ini = :base
# %d is the dir this configuration file is in
socket = %dapp.sock
master = true
processes = 4
max-requests = 1000 ; Restart workers after this many requests
max-worker-lifetime = 3600 ; Restart workers after this many seconds
reload-on-rss = 512 ; Restart workers after this much resident memory
worker-reload-mercy = 60 ; How long to wait before forcefully killing workers
我解决了这个问题。我认为它是由这个错误引起的。
uwsgi_response_write_body_do() TIMEOUT !!!
我添加睡眠并更改块大小。
# change chunk size from 512 byte to 1 MB, because it sleep 0.1 sec each loop.
def file_iterator(file, chunk_size=1024 * 1024):
with open(file, 'rb') as f:
while True:
time.sleep(0.1) # <-- add sleep
c = f.read(chunk_size)
if c:
yield c
else:
break
P.S。我试过了this solution。但是对我没有影响。
更新
当我检查自己下载的时候。它工作正常。但是请求延迟非常慢。大约15~18分钟。当我 运行 第一张图片时,大约是 0.2 ~ 0.3 秒。并且 Charged 容器实例时间增加了 5 倍。
1 小时
1 天
我觉得这个解决方案是急救。我钻了一些答案真正的解决方案。
更新 2021/11/02
我找到了真正的解决方案! uWSGI 套接字连接有一些问题。我改变了端口连接。现在我的申请 return 结果非常正常。
注意:这是正常的uWSGI PORT连接设置。