import {getInstanceMethods} from "../../util" import {ComponentType, HttpMethodType} from "../../enum" import {ConstructorType, PojoType} from "../../type/type" import ContextContainer from "../ContextContainer" import express from 'express' import DecorateRegistCenter from "../DecorateRegistCenter" import {IControllerParam, IHttpSend, IStream, IUpload} from "../../type/interface" import BizException from "../../type/impl/exception/BizException" import ErrorModel from "../../type/impl/http/ErrorModel" import ExceptionModel from "../../type/impl/http/ExceptionModel" import SuccessModel from "../../type/impl/http/SuccessModel" import multer from 'multer' const uploader = multer({ dest: 'c:/uploaders' }) export default class ControllInterceptor{ private instance: PojoType constructor(instance: PojoType = {}){ this.instance = instance this.handler() } private getMethodParamValues(methodName: string, cost: ConstructorType): Array{ const {params = >[]} = DecorateRegistCenter return > params.filter(({propName, cost: paramCost}: IControllerParam) => { return (cost === paramCost && propName === methodName) }) } private getRequestValue(requestName: string, request: express.Request, methodType: string, response: express.Response): any{ if(requestName === 'headers'){ return request.headers }else if(requestName === 'request'){ return request }else if(requestName === 'response'){ return response }else{ let value if(['get', 'options', 'head'].includes(methodType)){ value = request.query[requestName] }else{ value = request.body[requestName] } return value } } public handler(): void{ const {type = '', route, cost: componentCost} = this.instance.meta.component const server = ContextContainer.getServer() const {httpSends, streams, uploads} = DecorateRegistCenter if(type === ComponentType.CONTROLLER){ const expressRouter: express.Router = express.Router() const {ownMethods, prototypeMethods} = getInstanceMethods(this.instance) const instanceMethods = [...ownMethods, ...prototypeMethods] httpSends.forEach(({cost, type, route: methodRoute, methodName}: IHttpSend) => { const findMethod = instanceMethods.find(({name}: Function) => (cost === componentCost && name === methodName)) const findStream: IStream | undefined = isStreamMethod(cost, methodName, streams) const findUpload: IUpload | undefined = isUploadMethod(cost, methodName, uploads) if(findMethod){ const methodType = HttpMethodType[type].toLowerCase() const handler = async (...args: Array) => { const [request, response] = args const paramValues = this.getMethodParamValues(methodName, cost) let newArgs = args if(paramValues && paramValues.length > 0){ paramValues.forEach((paramValue: IControllerParam, idx: number) => { const {requestName = '', require = false} = paramValue if(requestName){ let value = this.getRequestValue(requestName, request, methodType, response) if(require){ const valueType = typeof value if(!value){ response.send(JSON.stringify(new ExceptionModel({message: '参数<' + requestName + '不允许为空>', status: 800}))) }else if(valueType === 'string' && value.trim() === ''){ response.send(JSON.stringify(new ExceptionModel({message: '参数<' + requestName + '不允许为空>', status: 800}))) } } if(typeof value === 'string' && (/^\{.*:.*\}$/.test(value))){ try{ value = JSON.parse(value) }catch(err){} } newArgs[paramValues.length - idx - 1] = value } }) } try{ const process = await findMethod.apply(this.instance, newArgs) if(findStream){ const {mineType = ''} = findStream response.set('content-type', mineType) response.end(process.buffer) }else{ response.set('content-type', 'application/json; charset=utf-8') response.end(JSON.stringify(new SuccessModel(process))) } }catch(err){ if(err instanceof BizException){ const {status, message, data} = err response.send(JSON.stringify(new ExceptionModel({message, status, data}))) }else{ //注意!!! //err不一定是 Error的实例,有可能是Promise通过reject抛出的字符串 if(typeof err === 'string'){ response.send(JSON.stringify(new ErrorModel(err))) }else{ response.send(JSON.stringify(new ErrorModel(( err).message))) } } } } if(findUpload){ (expressRouter)[methodType](methodRoute, uploader.any(), handler) }else{ (expressRouter)[methodType](methodRoute, handler) } } }) server.use(route, expressRouter) } } } function isStreamMethod(cost: ConstructorType, methodName: string = '', streams: Array = []): IStream | undefined{ return streams.find(({cost: cost2, methodName: methodName2}: IStream) => (cost2 === cost && methodName === methodName2)) } function isUploadMethod(cost: ConstructorType, methodName: string = '', uploads: Array = []): IUpload | undefined{ return uploads.find(({cost: cost2, methodName: methodName2}: IUpload) => (cost2 === cost && methodName === methodName2)) }