@halsp/http
Version:
支持 Halsp HTTP 请求
111 lines (99 loc) • 3.02 kB
text/typescript
import { Stream } from "stream";
import * as mime from "mime-types";
import {
HookType,
isNil,
isObject,
isString,
Response,
Startup,
} from "@halsp/core";
import { HttpException, InternalServerErrorException } from "./exceptions";
import { MapMatcher, ParsedRegister, parsePattern } from "./map-matcher";
import { HttpOptions } from "./options";
declare module "@halsp/core" {
interface Startup {
useHttp(options?: HttpOptions): this;
get parsedRegisters(): ParsedRegister[];
}
}
const usedMap = new WeakMap<Startup, boolean>();
Startup.prototype.useHttp = function (options: HttpOptions = {}) {
if (usedMap.get(this)) {
return this;
}
usedMap.set(this, true);
process.env.HALSP_ENV = "http";
Object.defineProperty(this, "parsedRegisters", {
enumerable: true,
configurable: true,
get: () => this.registers.map((r) => parsePattern(r)),
});
return this.use(async (ctx, next) => {
await new MapMatcher(ctx, options).match();
await next();
setType(ctx.res);
}).hook(HookType.Unhandled, (ctx, md, error) => {
const catchError = (err: Error | any) => {
if (err instanceof HttpException) {
ctx.res
.setHeaders(err.headers)
.setStatus(err.status)
.setBody(err.toPlainObject());
} else if (err instanceof Error) {
const msg = err.message || undefined;
const ex = new InternalServerErrorException(msg);
ex.inner = err;
catchError(ex);
} else if (isObject(err)) {
const ex = new InternalServerErrorException(err);
ex.inner = err;
catchError(ex);
} else {
const error = (!isNil(err) && String(err)) || undefined;
const ex = new InternalServerErrorException(error);
ex.inner = err;
catchError(ex);
}
};
catchError(error);
});
};
function setType(res: Response) {
const body = res.body;
if (!body) {
res.removeHeader("content-type");
res.removeHeader("content-length");
return res;
}
const writeType = !res.hasHeader("content-type");
const writeLength = !res.hasHeader("content-length");
if (Buffer.isBuffer(body)) {
if (writeLength) {
res.setHeader("content-length", body.byteLength);
}
if (writeType) {
res.setHeader("content-type", mime.contentType("bin") as string);
}
} else if (body instanceof Stream) {
if (writeType) {
res.setHeader("content-type", mime.contentType("bin") as string);
}
} else if (isString(body)) {
if (writeLength) {
res.setHeader("content-length", Buffer.byteLength(body));
}
if (writeType) {
const type = /^\s*</.test(body) ? "html" : "text";
res.setHeader("content-type", mime.contentType(type) as string);
}
} else {
if (writeLength) {
res.setHeader("content-length", Buffer.byteLength(JSON.stringify(body)));
}
if (writeType) {
res.setHeader("content-type", mime.contentType("json") as string);
}
}
return res;
}