@@ -267,6 +267,7 @@ def __init__(self):
267267 self .signature_version = settings .s3_signature_version
268268 self .endpoint_url = settings .s3_endpoint_url or f"https://{ self .s3_hostname } "
269269 self .aws_session_token = settings .aws_session_token
270+ self .addressing_style = str (settings .s3_addressing_style or "auto" ).lower ()
270271 self .proxy = settings .s3_proxy
271272 self .session = aioboto3 .Session (
272273 aws_access_key_id = self .access_key_id ,
@@ -278,14 +279,26 @@ def __init__(self):
278279 # 如果提供了 s3_endpoint_url,则优先使用它
279280 self .endpoint_url = settings .s3_endpoint_url
280281
282+ def _client_config (self ) -> Config :
283+ config = {"signature_version" : self .signature_version }
284+ s3_config = {}
285+ if self .addressing_style in {"path" , "virtual" , "auto" }:
286+ s3_config ["addressing_style" ] = self .addressing_style
287+ if s3_config :
288+ config ["s3" ] = s3_config
289+ return Config (** config )
290+
291+ def _client (self ):
292+ return self .session .client (
293+ "s3" ,
294+ endpoint_url = self .endpoint_url ,
295+ aws_session_token = self .aws_session_token ,
296+ region_name = self .region_name ,
297+ config = self ._client_config (),
298+ )
299+
281300 async def save_file (self , file : UploadFile , save_path : str ):
282- async with self .session .client (
283- "s3" ,
284- endpoint_url = self .endpoint_url ,
285- aws_session_token = self .aws_session_token ,
286- region_name = self .region_name ,
287- config = Config (signature_version = self .signature_version ),
288- ) as s3 :
301+ async with self ._client () as s3 :
289302 # 使用 upload_fileobj 流式上传,避免将整个文件加载到内存
290303 await s3 .upload_fileobj (
291304 file .file ,
@@ -295,12 +308,7 @@ async def save_file(self, file: UploadFile, save_path: str):
295308 )
296309
297310 async def delete_file (self , file_code : FileCodes ):
298- async with self .session .client (
299- "s3" ,
300- endpoint_url = self .endpoint_url ,
301- region_name = self .region_name ,
302- config = Config (signature_version = self .signature_version ),
303- ) as s3 :
311+ async with self ._client () as s3 :
304312 await s3 .delete_object (
305313 Bucket = self .bucket_name , Key = await file_code .get_file_path ()
306314 )
@@ -310,12 +318,7 @@ async def get_file_response(self, file_code: FileCodes):
310318 filename = file_code .prefix + file_code .suffix
311319 content_length = None # 初始化为 None,表示未知大小
312320
313- async with self .session .client (
314- "s3" ,
315- endpoint_url = self .endpoint_url ,
316- region_name = self .region_name ,
317- config = Config (signature_version = self .signature_version ),
318- ) as s3 :
321+ async with self ._client () as s3 :
319322 # 尝试获取文件大小(HEAD请求)
320323 try :
321324 head_response = await s3 .head_object (
@@ -384,12 +387,7 @@ async def get_file_url(self, file_code: FileCodes):
384387 if self .proxy :
385388 return await get_file_url (file_code .code )
386389 else :
387- async with self .session .client (
388- "s3" ,
389- endpoint_url = self .endpoint_url ,
390- region_name = self .region_name ,
391- config = Config (signature_version = self .signature_version ),
392- ) as s3 :
390+ async with self ._client () as s3 :
393391 result = await s3 .generate_presigned_url (
394392 "get_object" ,
395393 Params = {
@@ -406,13 +404,7 @@ async def save_chunk(self, upload_id: str, chunk_index: int, chunk_data: bytes,
406404 注意:这里不使用 S3 原生的 multipart upload,而是将每个分片作为独立对象存储
407405 """
408406 chunk_key = str (Path (save_path ).parent / "chunks" / upload_id / f"{ chunk_index } .part" )
409- async with self .session .client (
410- 's3' ,
411- endpoint_url = self .endpoint_url ,
412- aws_session_token = self .aws_session_token ,
413- region_name = self .region_name ,
414- config = Config (signature_version = self .signature_version ),
415- ) as s3 :
407+ async with self ._client () as s3 :
416408 # 将分片作为独立对象上传
417409 await s3 .put_object (
418410 Bucket = self .bucket_name ,
@@ -432,13 +424,7 @@ async def merge_chunks(self, upload_id: str, chunk_info: UploadChunk, save_path:
432424 file_sha256 = hashlib .sha256 ()
433425 chunk_dir = str (Path (save_path ).parent / "chunks" / upload_id )
434426
435- async with self .session .client (
436- 's3' ,
437- endpoint_url = self .endpoint_url ,
438- aws_session_token = self .aws_session_token ,
439- region_name = self .region_name ,
440- config = Config (signature_version = self .signature_version ),
441- ) as s3 :
427+ async with self ._client () as s3 :
442428 # 创建 multipart upload
443429 mpu = await s3 .create_multipart_upload (
444430 Bucket = self .bucket_name ,
@@ -512,13 +498,7 @@ async def clean_chunks(self, upload_id: str, save_path: str):
512498 :param save_path: 文件保存路径
513499 """
514500 chunk_dir = str (Path (save_path ).parent / "chunks" / upload_id )
515- async with self .session .client (
516- 's3' ,
517- endpoint_url = self .endpoint_url ,
518- aws_session_token = self .aws_session_token ,
519- region_name = self .region_name ,
520- config = Config (signature_version = self .signature_version ),
521- ) as s3 :
501+ async with self ._client () as s3 :
522502 try :
523503 # 列出并删除所有分片对象
524504 paginator = s3 .get_paginator ('list_objects_v2' )
@@ -540,13 +520,7 @@ async def generate_presigned_upload_url(self, save_path: str, expires_in: int =
540520 :param expires_in: URL过期时间(秒),默认15分钟
541521 :return: 预签名PUT URL
542522 """
543- async with self .session .client (
544- "s3" ,
545- endpoint_url = self .endpoint_url ,
546- aws_session_token = self .aws_session_token ,
547- region_name = self .region_name ,
548- config = Config (signature_version = self .signature_version ),
549- ) as s3 :
523+ async with self ._client () as s3 :
550524 return await s3 .generate_presigned_url (
551525 "put_object" ,
552526 Params = {
0 commit comments