UNPKG

node-web-mvc

Version:
161 lines (160 loc) 7.44 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * @module ResourceHttpRequestHandler * @description 静态资源请求处理器 */ const path_1 = __importDefault(require("path")); const HttpMethod_1 = __importDefault(require("../http/HttpMethod")); const HttpRequestMethodNotSupportedException_1 = __importDefault(require("../../errors/HttpRequestMethodNotSupportedException")); const Resource_1 = __importDefault(require("./Resource")); const HttpRequestValidation_1 = __importDefault(require("../http/HttpRequestValidation")); const ResourceCacheControl_1 = __importDefault(require("./ResourceCacheControl")); const HttpHeaders_1 = __importDefault(require("../http/HttpHeaders")); const HttpResource_1 = __importDefault(require("./HttpResource")); const HttpStatus_1 = __importDefault(require("../http/HttpStatus")); const ResourceRegion_1 = __importDefault(require("./ResourceRegion")); const GzipResource_1 = __importDefault(require("./GzipResource")); const PathResourceResolver_1 = __importDefault(require("./PathResourceResolver")); const GzipResourceTransformer_1 = __importDefault(require("./GzipResourceTransformer")); const ResourceHttpMessageConverter_1 = __importDefault(require("../http/converts/ResourceHttpMessageConverter")); const ResourceRegionHttpMessageConverter_1 = __importDefault(require("../http/converts/ResourceRegionHttpMessageConverter")); const RegionsResource_1 = __importDefault(require("./RegionsResource")); const DefaultResourceTransformerChain_1 = __importDefault(require("./DefaultResourceTransformerChain")); const HandlerMapping_1 = require("../mapping/HandlerMapping"); const DefaultResourceResolverChain_1 = __importDefault(require("./DefaultResourceResolverChain")); class ResourceHttpRequestHandler { constructor(registration, config) { // 允许使用的请求方式 this.allowHeaders = [HttpMethod_1.default.GET, HttpMethod_1.default.HEAD]; this.registration = registration; this.resourceConfig = config; this.resourceHttpMessageConverter = new ResourceHttpMessageConverter_1.default(); this.resourceRegionHttpMessageConverter = new ResourceRegionHttpMessageConverter_1.default(); } initResolversAndTransformers() { if (!this.resourceResolverChain) { const resolvers = [ new PathResourceResolver_1.default(), ]; const transformers = [ new GzipResourceTransformer_1.default(this.resourceConfig), ]; if (this.registration.resourceChainRegistration) { resolvers.push(...this.registration.resourceChainRegistration.resolvers); transformers.push(...this.registration.resourceChainRegistration.transformers); } this.resourceResolverChain = new DefaultResourceResolverChain_1.default(resolvers); this.resourceTransformerChain = new DefaultResourceTransformerChain_1.default(this.resourceResolverChain, transformers); } } /** * 处理静态资源请求 */ async handleRequest(request, response) { this.initResolversAndTransformers(); const servletContext = request.servletContext; // 校验请求 const resource = await this.checkRequest(request, response); if (!resource) { return; } // 配置缓存 new ResourceCacheControl_1.default(request, response, this.registration.cacheControl); // Head 请求支持 if (request.method === HttpMethod_1.default.HEAD) { this.setHeaders(response, resource); response.end(); return; } const ranges = request.getHeader(HttpHeaders_1.default.RANGE); if (ranges === null || ranges == undefined) { // 非断点下载 this.setHeaders(response, resource); await this.resourceHttpMessageConverter.write(resource, servletContext); return; } // 断点下载 response.setHeader(HttpHeaders_1.default.ACCEPT_RANGES, 'bytes'); try { const regions = ResourceRegion_1.default.getRangeRegions(request, resource); const regionsResource = new RegionsResource_1.default(regions, resource); await this.resourceRegionHttpMessageConverter.write(regionsResource, servletContext); } catch (ex) { response.setHeader('Content-Range', 'bytes */' + resource.contentLength); response.sendError(HttpStatus_1.default.REQUESTED_RANGE_NOT_SATISFIABLE); } } /** * 处理请求url * @param request */ processPath(request) { const url = request.getAttribute(HandlerMapping_1.HANDLE_MAPPING_PATH); return decodeURIComponent(url.replace(/\\/g, '/').replace(/\/\//g, '/').replace(/^\//, '')); } /** * 根据请求对象对应的静态资源 */ async getResource(request) { const resourcePath = this.processPath(request); const locations = this.registration.resourceLocations.map((url) => { url = url.endsWith(path_1.default.sep) ? url : url + path_1.default.sep; return new Resource_1.default(url); }); const resource = await this.resourceResolverChain.resolveResource(request, resourcePath, locations); return this.resourceTransformerChain.transform(request, resource); } /** * 校验请求谓词 */ async checkRequest(request, response) { const resource = await this.getResource(request); if (null === resource) { // 返回404 response.sendError(HttpStatus_1.default.NOT_FOUND); return; } if (request.method === HttpMethod_1.default.OPTIONS) { // 返回允许使用的方法 response.setHeader(HttpHeaders_1.default.ALLOW, this.allowHeaders.join(',')); response.end(); return; } if (this.allowHeaders.indexOf(request.method) < 0) { throw new HttpRequestMethodNotSupportedException_1.default(request.method, this.allowHeaders); } const validation = new HttpRequestValidation_1.default(request, response); if (validation.checkNotModified(null, resource.lastModified)) { return; } return resource; } /** * 设置资源文件返回头 */ setHeaders(response, resource) { // 设置content-length if (!(resource instanceof GzipResource_1.default)) { response.setHeader(HttpHeaders_1.default.CONTENT_LENGTH, resource.contentLength); } // 设置media-type if (resource.mediaType) { response.setHeader(HttpHeaders_1.default.CONTENT_TYPE, resource.mediaType.toString()); } // accept-ranges 支持 if (resource instanceof HttpResource_1.default) { const headers = resource.getResponseHeaders(); const keys = Object.keys(headers); keys.forEach((name) => { response.setHeader(name, headers[name]); }); response.setHeader(HttpHeaders_1.default.ACCEPT_RANGES, 'bytes'); } } } exports.default = ResourceHttpRequestHandler;