91 lines
2.7 KiB
TypeScript
Executable File
91 lines
2.7 KiB
TypeScript
Executable File
/**
|
||
* 模块: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()
|
||
}
|
||
}
|