常见的问题及解决方案
前端下载
Javascript 将{ “name”: “download” }转为 download.json 文件并下载
- 利用 a 标签 + DataURI
const data = { name: "download" };
const a = document.createElement("a");a.download = "download.json";a.href = `data:plain/text;base64,${btoa(JSON.stringify(data))}`; // base64或者URL编码都行
const ev = document.createEvent("MouseEvents");ev.initMouseEvent("click");a.dispatchEvent(ev);- 利用 a 标签 + ObjectURL
const data = { name: "download" };
const a = document.createElement("a");a.download = "download.json";a.innerHTML = "Download";a.href = URL.createObjectURL( new Blob([JSON.stringify(data)], { type: "plain/text" }));
const ev = document.createEvent("MouseEvents");ev.initMouseEvent("click");a.dispatchEvent(ev);PC、移动端公用域名,但不同代码时,避免错误缓存
- HTTP 响应头 Vary :Vary 为服务器返回的头部,表示在内容协商算法时,应该使用哪些头部信息
Vary: * // 所以请求视为唯一,但是最好使用的 Cache-Control: no-storeVary: <header-name>, <header-name>, ...
Vary: user-agent // 可以用来区分移动端还是PC端Office Excel 打开 *.csv 文件乱码
对于*.csv 文件,office excel 打开时,需要一个元信息来说明他的 BOM(Byte Order Mark),如果不存在这个元信息,office excel 会可能以非 unicode 编码打开,从而导致乱
**修复:**添加元信息 \uFEFF,标识为 unicode 小端序
Typescript paths 在 *.js 文件中无法使用
tsc 命令在运行后,未对 paths 内的路径进行还原,导致在运行*.js 文件时,无法识别路径
修复:
- hack require:在*.js 文件加载时,去识别路径,例如使用 module-alias
/** * 启动脚本 启动之前需要加载或者执行的程序 */import { addAliases } from "module-alias";
const cwd = process.cwd();
addAliases({ "@Src": `${cwd}/dist`, "@App": `${cwd}/dist/app`, "@Helper": `${cwd}/dist/helper`, "@Common": `${cwd}/dist/common`, "@Log": `${cwd}/dist/common/module/log`, "@Config": `${cwd}/dist/common/module/config`, "@Protocol": `${cwd}/protocol-buffers`, "@Public": `${cwd}+/public`,});- hack path:在 tsc 时,标明完整路径,例如使用 tsconfig-paths
import tsConfigPaths = require("tsconfig-paths");import { readFileSync } from "fs";import { join } from "path";
const tsconfig = JSON.parse( readFileSync(join(process.cwd(), "tsconfig.json")).toString());const { paths, baseUrl } = tsconfig.compilerOptions;
const cleanup = tsConfigPaths.register({ baseUrl, paths,});
cleanup();前端图片压缩
前端实现图片压缩非根据压缩算法,而是通过 Canvas API 合理的减少图片质量、裁剪尺寸,以减少体积
- 利用 FileReader API 读取文图片
- 利用 Canvas API 绘制图片
- 再利用 toDataURL、toBlob 压缩图片
canvas 图片跨域
使用 canvas 时,如下情况
/*@types {HTMLCanvasElement}*/const canvas = document.getElementById("canvas");const ctx = canvas.getContext("2d");
const img = new Image();// img.crossOrigin = '*'; 解决跨域的问题img.src = "https://t7.baidu.com/it/u=2880994680,1520946052&fm=193&f=GIF";
img.onload = function () { ctx.drawImage(img, 0, 0); canvas.toDataURL("image/png"); // 生成base64};在使用 toDataURL、getImageData 是会存在跨域问题,生成 URL 会报错,使用 img.crossOrigin = '*'** ** 解决跨域的问题
node.js GRPC 常见问题
- 客户端、服务端读取 metadata
- 客户端、服务端发送 metadata
- 拦截器
import { loadSync } from "@grpc/proto-loader";import { loadPackageDefinition, credentials, Metadata, StatusObject, InterceptingCall, Listener,} from "grpc";
const PB_ROOT_PATH = "";const PB_PATH = "";
const pb = loadSync(PB_PATH, { keepCase: true, includeDirs: [PB_ROOT_PATH],});
const Service = (loadPackageDefinition(pb).$PB_PACKAGE_NAME as any) .$PB_SERVICE_NAME;const client = new Service($SERVER_ADDRESS, credentials.createInsecure(), { interceptors: [interceptor],});
// 拦截器function interceptor(options: any, next: any) { return new InterceptingCall(next(options), { start(metadata: Metadata, listener: Listener, next: Function) { // 可以修改请求值的metadata统一拦截 metadata.add("Trace-Id", "12345");
// 可以对返回值进行拦截 next(metadata, { onReceiveMetadata(metadata: Metadata, next: Function) { console.log("receive metadata", metadata); next(metadata); }, onReceiveMessage(message: any, next: Function) { console.log("receive message", message); next(message); }, onReceiveStatus(status: StatusObject, next: Function) { console.log("receive status", status); next(status); }, }); }, });}
const mt = new Metadata();mt.add("trace-id", "123");
const res = client.TransText({ text: "岳智明" }, mt, (err: any, res: any) => { console.log(err); console.log(res);});node.js 获取在线人数
使用 web socket 实时记录
Server
const http = require("http");const socketIo = require("socket.io");
let userCount = 0;const server = http.createServer();const io = socketIo(server, { cors: { origin: "*", },});
io.on("connection", (client) => { userCount++; console.log("人数增加了一个,总计:", userCount); console.log(Object.keys(io.engine.clients).length); // 或者不采用计数,直接获取客户端的连接数
io.emit("user_count_change", userCount);
client.on("disconnect", () => { userCount--; console.log("人数减少了一个,总计:", userCount);
io.emit("user_count_change", userCount); });});
server.listen(3001);Client
// 记得引入 socket.io
const socket = io("localhost:3001");socket.on("connect", function () { console.log("连接服务端,开始计数");});
socket.on("user_count_change", (count) => { //});使用数据库实时记录,例如 redis
redis 记录当前有效的 session-id,实时扫描即可获得在线人数
pm2 报错
Error: spawn E2BIG
pm2 以 cluster 模式启动时,如果环境过多,可能会导致 spawn 报错 E2BIG(表示参数过长),导致报错
解决方法
- 删除无用的环境变量
- 使用 fork 模式
- 不使用 pm2,直接对 node.js 进行启动