/** * 模块:HeadHandler * 功能:处理TUS协议的HEAD请求,用于获取上传文件的状态信息 * 使用场景:在文件分片上传过程中,客户端需要定期查询上传进度时使用 */ import { CancellationContext, ERRORS, Upload, Metadata } from '../utils' import { BaseHandler } from './BaseHandler' import type http from 'node:http' /** * HeadHandler类 * 核心功能:处理TUS协议的HEAD请求,返回文件上传的元数据和进度信息 * 设计模式:继承自BaseHandler,采用模板方法模式 * 使用示例: * const handler = new HeadHandler(store, options) * await handler.send(req, res, context) */ export class HeadHandler extends BaseHandler { /** * 处理HEAD请求的核心方法 * @param req HTTP请求对象 * @param res HTTP响应对象 * @param context 取消操作的上下文 * @returns 返回HTTP响应 * @throws ERRORS.FILE_NOT_FOUND 文件ID不存在时抛出 * @throws ERRORS.FILE_NO_LONGER_EXISTS 文件已过期时抛出 */ async send( req: http.IncomingMessage, res: http.ServerResponse, context: CancellationContext ) { // 从请求中提取文件ID const id = this.getFileIdFromRequest(req) if (!id) { throw ERRORS.FILE_NOT_FOUND } // 执行自定义的请求预处理逻辑 if (this.options.onIncomingRequest) { await this.options.onIncomingRequest(req, res, id) } // 获取文件锁,防止并发操作 const lock = await this.acquireLock(req, id, context) let file: Upload try { // 从存储中获取文件上传信息 file = await this.store.getUpload(id) } finally { // 无论成功与否,都释放锁 await lock.unlock() } // 检查文件是否已过期 const now = new Date() if ( this.store.hasExtension('expiration') && this.store.getExpiration() > 0 && file.creation_date && now > new Date(new Date(file.creation_date).getTime() + this.store.getExpiration()) ) { throw ERRORS.FILE_NO_LONGER_EXISTS } // 设置响应头,防止缓存 res.setHeader('Cache-Control', 'no-store') // 返回当前上传偏移量 res.setHeader('Upload-Offset', file.offset) // 处理文件大小信息 if (file.sizeIsDeferred) { // 如果文件大小未知,设置延迟长度标志 res.setHeader('Upload-Defer-Length', '1') } else { // 如果文件大小已知,返回实际大小 res.setHeader('Upload-Length', file.size as number) } // 处理文件元数据 if (file.metadata !== undefined) { // 将元数据转换为字符串格式返回 res.setHeader('Upload-Metadata', Metadata.stringify(file.metadata) as string) } // 结束响应 return res.end() } }