Skip to content

Commit ade5799

Browse files
committed
fix: 仅在获取到文件大小时才设置 Content-Length 头
1 parent 6b728ab commit ade5799

File tree

1 file changed

+29
-23
lines changed

1 file changed

+29
-23
lines changed

core/storage.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,19 @@ async def get_file_response(self, file_code: FileCodes):
145145
encoded_filename = quote(filename, safe='')
146146
content_disposition = f"attachment; filename*=UTF-8''{encoded_filename}"
147147

148-
# 优先使用文件系统大小
149-
content_length = file_code.size # 默认使用数据库中的大小
148+
# 尝试获取文件系统大小,如果成功则设置 Content-Length
149+
headers = {"Content-Disposition": content_disposition}
150150
try:
151151
content_length = file_path.stat().st_size
152+
headers["Content-Length"] = str(content_length)
152153
except Exception:
153-
# 如果获取文件大小失败,继续使用默认大小
154+
# 如果获取文件大小失败,则不提供 Content-Length
154155
pass
155156

156157
return FileResponse(
157158
file_path,
158159
media_type="application/octet-stream",
159-
headers={"Content-Disposition": content_disposition, "Content-Length": str(content_length)},
160+
headers=headers,
160161
filename=filename # 保留原始文件名以备某些场景使用
161162
)
162163

@@ -305,15 +306,15 @@ async def delete_file(self, file_code: FileCodes):
305306
async def get_file_response(self, file_code: FileCodes):
306307
try:
307308
filename = file_code.prefix + file_code.suffix
308-
content_length = file_code.size # 默认使用数据库中的大小
309+
content_length = None # 初始化为 None,表示未知大小
309310

310311
async with self.session.client(
311312
"s3",
312313
endpoint_url=self.endpoint_url,
313314
region_name=self.region_name,
314315
config=Config(signature_version=self.signature_version),
315316
) as s3:
316-
# 首先尝试获取文件大小(HEAD请求)
317+
# 尝试获取文件大小(HEAD请求)
317318
try:
318319
head_response = await s3.head_object(
319320
Bucket=self.bucket_name,
@@ -325,7 +326,7 @@ async def get_file_response(self, file_code: FileCodes):
325326
elif 'Content-Length' in head_response['ResponseMetadata']['HTTPHeaders']:
326327
content_length = int(head_response['ResponseMetadata']['HTTPHeaders']['Content-Length'])
327328
except Exception:
328-
# 如果HEAD请求失败,继续使用默认大小
329+
# 如果HEAD请求失败,则不提供 Content-Length
329330
pass
330331

331332
link = await s3.generate_presigned_url(
@@ -361,9 +362,10 @@ async def stream_generator():
361362
from fastapi.responses import StreamingResponse
362363
encoded_filename = quote(filename, safe='')
363364
headers = {
364-
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}",
365-
"Content-Length": str(content_length)
365+
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"
366366
}
367+
if content_length is not None:
368+
headers["Content-Length"] = str(content_length)
367369
return StreamingResponse(
368370
stream_generator(),
369371
media_type="application/octet-stream",
@@ -650,7 +652,7 @@ async def get_file_response(self, file_code: FileCodes):
650652
self._get_file_url, await file_code.get_file_path(), filename
651653
)
652654

653-
content_length = file_code.size # 默认使用数据库中的大小
655+
content_length = None # 初始化为 None,表示未知大小
654656

655657
# 创建ClientSession并复用
656658
session = aiohttp.ClientSession()
@@ -661,7 +663,7 @@ async def get_file_response(self, file_code: FileCodes):
661663
if resp.status == 200 and 'Content-Length' in resp.headers:
662664
content_length = int(resp.headers['Content-Length'])
663665
except Exception:
664-
# 如果HEAD请求失败,继续使用默认大小
666+
# 如果HEAD请求失败,则不提供 Content-Length
665667
pass
666668

667669
async def stream_generator():
@@ -683,9 +685,10 @@ async def stream_generator():
683685

684686
encoded_filename = quote(filename, safe='')
685687
headers = {
686-
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}",
687-
"Content-Length": str(content_length)
688+
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"
688689
}
690+
if content_length is not None:
691+
headers["Content-Length"] = str(content_length)
689692
return StreamingResponse(
690693
stream_generator(),
691694
media_type="application/octet-stream",
@@ -853,7 +856,7 @@ async def get_file_url(self, file_code: FileCodes):
853856
async def get_file_response(self, file_code: FileCodes):
854857
try:
855858
filename = file_code.prefix + file_code.suffix
856-
content_length = file_code.size # 默认使用数据库中的大小
859+
content_length = None # 初始化为 None,表示未知大小
857860

858861
# 尝试获取文件大小
859862
try:
@@ -863,7 +866,7 @@ async def get_file_response(self, file_code: FileCodes):
863866
elif hasattr(stat_result, 'size') and stat_result.size:
864867
content_length = stat_result.size
865868
except Exception:
866-
# 如果获取大小失败,继续使用默认大小
869+
# 如果获取大小失败,则不提供 Content-Length
867870
pass
868871

869872
# 尝试使用流式读取器
@@ -875,9 +878,10 @@ async def get_file_response(self, file_code: FileCodes):
875878
content = await self.operator.read(await file_code.get_file_path())
876879
encoded_filename = quote(filename, safe='')
877880
headers = {
878-
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}",
879-
"Content-Length": str(content_length)
881+
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"
880882
}
883+
if content_length is not None:
884+
headers["Content-Length"] = str(content_length)
881885
return Response(
882886
content, headers=headers, media_type="application/octet-stream"
883887
)
@@ -892,9 +896,10 @@ async def stream_generator():
892896

893897
encoded_filename = quote(filename, safe='')
894898
headers = {
895-
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}",
896-
"Content-Length": str(content_length)
899+
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"
897900
}
901+
if content_length is not None:
902+
headers["Content-Length"] = str(content_length)
898903
return StreamingResponse(
899904
stream_generator(),
900905
media_type="application/octet-stream",
@@ -1087,7 +1092,7 @@ async def get_file_response(self, file_code: FileCodes):
10871092
try:
10881093
filename = file_code.prefix + file_code.suffix
10891094
url = self._build_url(await file_code.get_file_path())
1090-
content_length = file_code.size # 默认使用数据库中的大小
1095+
content_length = None # 初始化为 None,表示未知大小
10911096

10921097
# 创建ClientSession并复用(包含认证头)
10931098
session = aiohttp.ClientSession(headers={
@@ -1100,7 +1105,7 @@ async def get_file_response(self, file_code: FileCodes):
11001105
if resp.status == 200 and 'Content-Length' in resp.headers:
11011106
content_length = int(resp.headers['Content-Length'])
11021107
except Exception:
1103-
# 如果HEAD请求失败,继续使用默认大小
1108+
# 如果HEAD请求失败,则不提供 Content-Length
11041109
pass
11051110

11061111
async def stream_generator():
@@ -1122,9 +1127,10 @@ async def stream_generator():
11221127

11231128
encoded_filename = quote(filename, safe='')
11241129
headers = {
1125-
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}",
1126-
"Content-Length": str(content_length)
1130+
"Content-Disposition": f"attachment; filename*=UTF-8''{encoded_filename}"
11271131
}
1132+
if content_length is not None:
1133+
headers["Content-Length"] = str(content_length)
11281134
return StreamingResponse(
11291135
stream_generator(),
11301136
media_type="application/octet-stream",

0 commit comments

Comments
 (0)