web-font/backend/app.ts
2024-08-18 16:29:18 +08:00

119 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import fs, { readFile } from "fs/promises";
import * as path from "path";
import { fontSubset } from "./font_util/font";
import { mimeTypes } from "./server/mime_type";
import type { cMiddleware } from "./server/req_res";
import { SimpleHttpServer } from "./server/server";
const ROOT_DIR = path.resolve("dist"); // 静态文件目录
const staticFileMiddleware: cMiddleware = async function (req, res, next) {
if (req.method === "GET") {
const filePath = path.join(ROOT_DIR, req.url === "/" ? "index.html" : req.url);
try {
const stats = await fs.stat(filePath);
if (stats.isFile()) {
const fileContent = await fs.readFile(filePath);
const extname = path.extname(filePath);
res.statusCode = 200;
res.headers["Content-Type"] = mimeTypes[extname] || "application/octet-stream";
res.headers["Content-Length"] = `${stats.size}`;
res.body = fileContent;
} else {
// 文件不存在
res.statusCode = 404;
res.headers["Content-Type"] = "text/plain";
res.body = "404 Not Found";
}
} catch (err) {
// 错误处理
res.statusCode = 404;
res.headers["Content-Type"] = "text/plain";
res.body = `404 Not Found`;
}
} else {
// 返回 405 Method Not Allowed
res.statusCode = 405;
res.headers["Content-Type"] = "text/plain";
res.body = "Method Not Allowed";
}
return next(req, res);
};
const logMiddleware: cMiddleware = async (req, res, next) => {
const t1 = Date.now();
const r = await next(req, res);
const t2 = Date.now();
console.log(`[${t2 - t1}ms] ${req.url}`);
return r;
};
const corsMiddleware: cMiddleware = async (req, res, next) => {
// 允许所有域跨域请求
res.headers["Access-Control-Allow-Origin"] = "*";
// 如果你只想允许特定域名:
// res.headers["Access-Control-Allow-Origin"] = "https://example.com";
// 允许常见的 HTTP 方法
res.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS";
// 允许的请求头
res.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization";
// 如果是 OPTIONS 请求(预检请求),直接返回成功响应
if (req.method === "OPTIONS") {
res.statusCode = 204;
res.headers["Content-Length"] = "0";
res.body = "";
// 直接结束请求,不继续传递到下一个中间件
return { req, res };
} else {
return next(req, res);
}
};
const fontCache: { [key: string]: any } = {};
const ttfCache: { [key: string]: any } = {};
const fontApiMiddleware: cMiddleware = async (req, res, next) => {
if (!req.url.startsWith("/api")) return next(req, res);
res.statusCode = 200;
res.headers["Content-Type"] = "font/ttf";
// 创建一个新的 URL 对象(需要一个完整的 URL必须包含协议和主机
const url = new URL(req.url, "http://test.com");
// 使用 URLSearchParams 来解析查询参数
const params = new URLSearchParams(url.search);
// 获取参数的值
const font = params.get("font") || "";
const text = params.get("text") || "";
const path = `font/${font}`;
const fontType = path.split(".").pop() as "ttf";
if (ttfCache[req.url]) {
// @ts-ignore
res.body = ttfCache[req.url];
return { req, res };
}
const oldFontBuffer = fontCache[path] ?? new Uint8Array(await readFile(path)).buffer;
fontCache[path] = oldFontBuffer;
const outType = "ttf";
const newFont = await fontSubset(oldFontBuffer, text, {
outType: outType,
sourceType: fontType,
});
// @ts-ignore
res.body = newFont;
ttfCache[req.url] = newFont;
return { req, res };
};
const server = new SimpleHttpServer({ port: 8087 });
server.use(logMiddleware, corsMiddleware, fontApiMiddleware, staticFileMiddleware);
// const main = async () => {
// // const path = "backend/问藏书房.ttf"; //问藏书房
// const path = "backend/令东齐伋复刻体.ttf";
// // const path = "./backend/GoodHood-2.otf";//英文字体
// const fontType = path.split(".").pop() as "ttf";
// const oldFontBuffer = new Uint8Array(await readFile(path)).buffer;
// const outType = "ttf";
// const newFont = await fontSubset(oldFontBuffer, "abc问书房令东齐伋复刻体", {
// outType: outType,
// sourceType: fontType,
// });
// writeFile(`./public/font.${outType}`, newFont);
// };