class FilePreviewHandler(tornado.web.RequestHandler):
async def get(self):
pool_name = self.get_argument("pool")
raw_file_name = self.get_argument("file")
file_name = urllib.parse.unquote(raw_file_name)
if pool_name not in RESOURCE_POOLS:
self.set_status(404)
self.render("404.html")
return
pool_path = RESOURCE_POOLS[pool_name]["path"]
file_path = os.path.normpath(os.path.join(pool_path, file_name))
real_request_path = os.path.realpath(file_path)
real_pool_path = os.path.realpath(pool_path)
if not real_request_path.startswith(real_pool_path):
self.set_status(403)
self.write("禁止访问此文件路径")
return
if not os.path.exists(file_path):
self.set_status(404)
self.render("404.html")
return
ext = os.path.splitext(file_name)[1].lower()
# 特别处理 PDF 文件:使用本地 PDF.js 预览
if ext == ".pdf":
# 构造预览链接,不要双重编码
proxy_url = f"/preview?pool={pool_name}&file={urllib.parse.quote(file_name)}"
# 传递原始 URL,不要再次编码
pdf_url = f"/static/pdfjs/web/viewer.html?file={proxy_url}"
self.redirect(pdf_url)
return
# 设置 MIME 类型
mime_type = {
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'.pdf': 'application/pdf',
'.txt': 'text/plain',
'.md': 'text/markdown',
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.mp4': 'video/mp4',
'.webm': 'video/webm',
'.ogg': 'video/ogg',
'.mp3': 'audio/mpeg',
'.wav': 'audio/wav',
'.flac': 'audio/flac',
}.get(ext, mimetypes.guess_type(file_name)[0] or 'application/octet-stream')
encoded_filename = urllib.parse.quote(file_name.encode('utf-8'))
self.set_header("Content-Disposition", f'inline; filename*=UTF-8\'\'{encoded_filename}')
file_size = os.path.getsize(file_path)
range_header = self.request.headers.get('Range')
is_download = not range_header and ext in ['.mp4', '.webm', '.ogg', '.pdf']
if is_download:
self.set_header('Content-Type', mime_type)
self.set_header('Content-Length', str(file_size))
self.set_status(200)
if os.name == 'posix':
fd = os.open(file_path, os.O_RDONLY)
try:
await tornado.ioloop.IOLoop.current().run_in_executor(
None,
os.sendfile,
self.request.connection.fileno(),
fd,
None,
file_size
)
finally:
os.close(fd)
else:
with open(file_path, 'rb') as f:
while True:
chunk = f.read(1024 * 1024 * 4)
if not chunk:
break
try:
self.write(chunk)
await self.flush()
except tornado.iostream.StreamClosedError:
return
self.finish()
elif ext in ['.mp4', '.webm', '.ogg', '.pdf', '.mp3', '.wav', '.flac']:
self.set_header('Accept-Ranges', 'bytes')
start = 0
end = file_size - 1
if range_header:
self.set_status(206)
start_bytes, end_bytes = range_header.replace('bytes=', '').split('-')
start = int(start_bytes) if start_bytes else 0
end = int(end_bytes) if end_bytes else file_size - 1
self.set_header('Content-Range', f'bytes {start}-{end}/{file_size}')
self.set_header("Content-Length", str(end - start + 1))
self.set_header('Content-Type', mime_type)
chunk_size = 4096 * 16
async with aiofiles.open(file_path, 'rb') as f:
await f.seek(start)
remaining = end - start + 1
while remaining > 0:
chunk = await f.read(min(chunk_size, remaining))
if not chunk:
break
try:
self.write(chunk)
await self.flush()
except tornado.iostream.StreamClosedError:
return
remaining -= len(chunk)
self.finish()
elif ext == '.txt':
self.set_header('Content-Type', 'text/plain; charset=UTF-8')
async with aiofiles.open(file_path, 'r', encoding='utf-8') as f:
content = await f.read()
self.write(content)
self.finish()
elif ext in ['.png', '.jpg', '.jpeg', '.gif', '.md', '.pdf', '.docx', '.xlsx', '.pptx']:
self.set_header('Content-Type', mime_type)
async with aiofiles.open(file_path, 'rb') as f:
data = await f.read()
self.write(data)
self.finish()
else:
self.set_status(400)
self.write("不支持预览此文件类型")
这是我的这个方法,你在我提供的这个方法代码中修改后给我把修改后的方法代码完整的给我提供过来吧