| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- 'use strict';
- // 通用小工具:响应、请求体、文件名/扩展名处理(无状态,可被任意层引用)
- const path = require('path');
- const MAX_BODY_BYTES = 32 * 1024 * 1024;
- const IMAGE_EXT = new Set(['.jpg', '.jpeg', '.png', '.webp', '.gif']);
- const MIME_BY_EXT = {
- '.jpg': 'image/jpeg',
- '.jpeg': 'image/jpeg',
- '.png': 'image/png',
- '.webp': 'image/webp',
- '.gif': 'image/gif',
- };
- // 采集输出根目录下永远跳过的目录名
- const SKIP_DIR_NAMES = new Set(['膳绘']);
- function sendJson(res, statusCode, obj) {
- const data = JSON.stringify(obj);
- res.writeHead(statusCode, { 'Content-Type': 'application/json; charset=utf-8' });
- res.end(data);
- }
- function sleep(ms) {
- return new Promise((resolve) => setTimeout(resolve, ms));
- }
- function sanitizeFileName(name) {
- return String(name).replace(/[\\/:*?"<>|]/g, '_').trim() || 'file';
- }
- function readBody(req) {
- return new Promise((resolve, reject) => {
- const chunks = [];
- let size = 0;
- req.on('data', (c) => chunks.push(c));
- req.on('data', (c) => {
- size += c.length;
- if (size > MAX_BODY_BYTES) {
- req.destroy(new Error('请求体过大'));
- reject(new Error('请求体过大'));
- }
- });
- req.on('end', () => {
- if (!chunks.length) return resolve({});
- try {
- resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')));
- } catch (e) {
- reject(e);
- }
- });
- req.on('error', reject);
- });
- }
- function guessExtFromUrl(urlStr) {
- try {
- const u = new URL(urlStr);
- let ext = path.extname(u.pathname).replace('.', '').toLowerCase();
- if (ext === 'jpeg') ext = 'jpg';
- if (['jpg', 'png', 'gif', 'webp'].includes(ext)) return ext;
- } catch {
- // fall through
- }
- return 'jpg';
- }
- module.exports = {
- MAX_BODY_BYTES,
- IMAGE_EXT,
- MIME_BY_EXT,
- SKIP_DIR_NAMES,
- sendJson,
- sleep,
- sanitizeFileName,
- readBody,
- guessExtFromUrl,
- };
|