# 文件访问使用指南 本文档说明如何使用 `@repo/storage` 包提供的文件访问功能。 ## 功能概述 存储包提供统一的文件访问接口: - **统一下载接口** (`/download/:fileId`) - 适用于所有存储类型,提供统一的文件访问 ## 使用方法 ### 1. 基础配置 ```typescript import { createStorageApp } from '@repo/storage'; // 创建包含所有功能的存储应用 const storageApp = createStorageApp({ apiBasePath: '/api/storage', // API 管理接口 uploadPath: '/upload', // TUS 上传接口 downloadPath: '/download', // 文件下载接口 }); app.route('/', storageApp); ``` ### 2. 分别配置功能 ```typescript import { createStorageRoutes, createTusUploadRoutes, createFileDownloadRoutes } from '@repo/storage'; const app = new Hono(); // 存储管理 API app.route('/api/storage', createStorageRoutes()); // 文件上传 app.route('/upload', createTusUploadRoutes()); // 文件下载(所有存储类型) app.route('/download', createFileDownloadRoutes()); ``` ## 文件访问方式 ### 统一下载接口 无论使用哪种存储类型,都通过统一的下载接口访问文件: ```bash # 访问文件(支持内联显示和下载) GET http://localhost:3000/download/2024/01/01/abc123/image.jpg GET http://localhost:3000/download/2024/01/01/abc123/document.pdf ``` ### 本地存储 当 `STORAGE_TYPE=local` 时: - 下载接口直接读取本地文件 - 自动设置正确的 Content-Type - 支持内联显示(`Content-Disposition: inline`) ### S3 存储 当 `STORAGE_TYPE=s3` 时: - 下载接口重定向到 S3 URL - 也可以直接访问 S3 URL(如果存储桶是公开的) ```bash # 直接访问 S3 URL(如果存储桶是公开的) GET https://bucket.s3.region.amazonaws.com/2024/01/01/abc123/file.jpg ``` ## 代码示例 ### 生成文件访问 URL ```typescript import { StorageUtils } from '@repo/storage'; const storageUtils = StorageUtils.getInstance(); // 生成文件访问 URL function getFileUrl(fileId: string) { // 结果: http://localhost:3000/download/2024/01/01/abc123/file.jpg return storageUtils.generateFileUrl(fileId); } // 生成完整的公开访问 URL function getPublicFileUrl(fileId: string) { // 结果: https://yourdomain.com/download/2024/01/01/abc123/file.jpg return storageUtils.generateFileUrl(fileId, 'https://yourdomain.com'); } // 生成 S3 直接访问 URL(仅 S3 存储) function getDirectUrl(fileId: string) { try { // S3 存储: https://bucket.s3.region.amazonaws.com/2024/01/01/abc123/file.jpg return storageUtils.generateDirectUrl(fileId); } catch (error) { // 本地存储会抛出错误,使用下载接口 return storageUtils.generateFileUrl(fileId); } } ``` ### 在 React 组件中使用 ```tsx import { useState, useEffect } from 'react'; function FileDisplay({ fileId }: { fileId: string }) { const [fileUrl, setFileUrl] = useState(''); useEffect(() => { // 获取文件访问 URL fetch(`/api/storage/resource/${fileId}`) .then((res) => res.json()) .then((data) => { if (data.status === 'ready' && data.resource) { // 生成文件访问 URL const url = `/download/${fileId}`; setFileUrl(url); } }); }, [fileId]); if (!fileUrl) return
Loading...
; return (
{/* 图片会内联显示 */} Uploaded file {/* 下载链接 */} 下载文件 {/* PDF 等文档可以在新窗口打开 */} 在新窗口打开
); } ``` ### 文件类型处理 ```typescript function getFileDisplayUrl(fileId: string, mimeType: string) { const baseUrl = `/download/${fileId}`; // 根据文件类型决定显示方式 if (mimeType.startsWith('image/')) { // 图片直接显示 return baseUrl; } else if (mimeType === 'application/pdf') { // PDF 可以内联显示 return baseUrl; } else { // 其他文件类型强制下载 return `${baseUrl}?download=true`; } } ``` ## 安全考虑 ### 1. 访问控制 如需要权限验证,可以添加认证中间件: ```typescript import { createFileDownloadRoutes } from '@repo/storage'; const app = new Hono(); // 添加认证中间件 app.use('/download/*', async (c, next) => { // 检查用户权限 const token = c.req.header('Authorization'); if (!isValidToken(token)) { return c.json({ error: 'Unauthorized' }, 401); } await next(); }); // 添加文件下载服务 app.route('/download', createFileDownloadRoutes()); ``` ### 2. 文件类型限制 ```typescript app.use('/download/*', async (c, next) => { const fileId = c.req.param('fileId'); // 从数据库获取文件信息 const { resource } = await getResourceByFileId(fileId); if (!resource) { return c.json({ error: 'File not found' }, 404); } // 检查文件类型 const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf']; if (!allowedTypes.includes(resource.mimeType)) { return c.json({ error: 'File type not allowed' }, 403); } await next(); }); ``` ## 性能优化 ### 1. 缓存设置 ```typescript app.use('/download/*', async (c, next) => { await next(); // 设置缓存头 c.header('Cache-Control', 'public, max-age=31536000'); // 1年 c.header('ETag', generateETag(c.req.path)); }); ``` ### 2. CDN 配置 对于生产环境,建议使用 CDN: ```typescript import { StorageUtils } from '@repo/storage'; const storageUtils = StorageUtils.getInstance(); // 使用 CDN 域名 const cdnUrl = 'https://cdn.yourdomain.com'; const fileUrl = storageUtils.generateFileUrl(fileId, cdnUrl); ``` ## 故障排除 ### 常见问题 1. **404 文件未找到** - 检查文件是否存在于数据库 - 确认文件路径是否正确 - 检查文件权限(本地存储) 2. **下载接口不工作** - 检查路由配置 - 确认存储配置正确 - 查看服务器日志 3. **S3 文件无法访问** - 检查 S3 存储桶权限 - 确认文件是否上传成功 - 验证 S3 配置是否正确 ### 调试方法 ```bash # 检查文件是否存在 curl -I http://localhost:3000/download/2024/01/01/abc123/file.jpg # 检查存储配置 curl http://localhost:3000/api/storage/storage/info # 检查文件信息 curl http://localhost:3000/api/storage/resource/2024/01/01/abc123/file.jpg ```