1
1
# coding=utf-8
2
+ import re
2
3
import urllib
3
4
4
5
import uuid_utils .compat as uuid
54
55
"csv" : "text/csv" , "tsv" : "text/tab-separated-values" , "ics" : "text/calendar" ,
55
56
}
56
57
58
+ # 如果是音频文件并且有range请求,处理部分内容
59
+ audio_types = ['mp3' , 'wav' , 'ogg' , 'flac' , 'aac' , 'opus' , 'm4a' ]
60
+
57
61
58
62
class FileSerializer (serializers .Serializer ):
59
63
file = UploadedFileField (required = True , label = _ ('file' ))
@@ -85,6 +89,10 @@ def upload(self, with_valid=True):
85
89
86
90
class Operate (serializers .Serializer ):
87
91
id = serializers .UUIDField (required = True )
92
+ http_range = serializers .CharField (
93
+ required = False , allow_blank = True , allow_null = True , label = _ ('HTTP Range' ),
94
+ help_text = _ ('HTTP Range header for partial content requests, e.g., "bytes=0-1023"' )
95
+ )
88
96
89
97
def get (self , with_valid = True ):
90
98
if with_valid :
@@ -96,16 +104,53 @@ def get(self, with_valid=True):
96
104
file_type = file .file_name .split ("." )[- 1 ].lower ()
97
105
content_type = mime_types .get (file_type , 'application/octet-stream' )
98
106
encoded_filename = urllib .parse .quote (file .file_name )
107
+ # 获取文件内容
108
+ file_bytes = file .get_bytes ()
109
+ file_size = len (file_bytes )
110
+
111
+ response = None
112
+ if file_type in audio_types and self .data .get ('http_range' ):
113
+ response = self .handle_audio (file_size , file_bytes , content_type , encoded_filename )
114
+ if response :
115
+ return response
116
+
117
+ # 对于非范围请求或其他类型文件,返回完整内容
99
118
headers = {
100
119
'Content-Type' : content_type ,
101
120
'Content-Disposition' : f'{ "inline" if file_type == "pdf" else "attachment" } ; filename={ encoded_filename } '
102
121
}
103
122
return HttpResponse (
104
- file . get_bytes () ,
123
+ file_bytes ,
105
124
status = 200 ,
106
125
headers = headers
107
126
)
108
127
128
+ def handle_audio (self , file_size , file_bytes , content_type , encoded_filename ):
129
+
130
+ # 解析range请求 (格式如 "bytes=0-1023")
131
+ range_match = re .match (r'bytes=(\d+)-(\d*)' , self .data .get ('http_range' , '' ))
132
+ if range_match :
133
+ start = int (range_match .group (1 ))
134
+ end = int (range_match .group (2 )) if range_match .group (2 ) else file_size - 1
135
+
136
+ # 确保范围合法
137
+ end = min (end , file_size - 1 )
138
+ length = end - start + 1
139
+
140
+ # 创建部分响应
141
+ response = HttpResponse (
142
+ file_bytes [start :start + length ],
143
+ status = 206 ,
144
+ content_type = content_type
145
+ )
146
+
147
+ # 设置部分内容响应头
148
+ response ['Content-Range' ] = f'bytes { start } -{ end } /{ file_size } '
149
+ response ['Accept-Ranges' ] = 'bytes'
150
+ response ['Content-Length' ] = str (length )
151
+ response ['Content-Disposition' ] = f'inline; filename={ encoded_filename } '
152
+ return response
153
+
109
154
def delete (self ):
110
155
self .is_valid (raise_exception = True )
111
156
file_id = self .data .get ('id' )
0 commit comments