node-web-mvc
Version:
node spring mvc
161 lines (160 loc) • 7.44 kB
JavaScript
"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;