Files
wechatWeb/api/service/biz_proxy_service.js
张成 084c437096 1
2026-04-01 14:23:57 +08:00

119 lines
3.3 KiB
JavaScript
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.
const axios = require("axios");
const baseModel = require("../../middleware/baseModel");
const config = require("../../config/config");
const logs = require("../../tool/logs_proxy");
const upstreamBaseUrl = config.upstream_api_url || "http://127.0.0.1:8888";
/** 写入日志用:序列化响应并截断,避免 TEXT 过大 */
const RESPONSE_BODY_MAX_LEN = 16000;
function serialize_response_for_log(data) {
if (data === undefined || data === null) return "";
let s;
if (typeof data === "string") s = data;
else {
try {
s = JSON.stringify(data);
} catch (e) {
s = String(data);
}
}
if (s.length > RESPONSE_BODY_MAX_LEN) {
return `${s.slice(0, RESPONSE_BODY_MAX_LEN)}…[truncated]`;
}
return s;
}
/**
* 转发请求到上游并记录调用日志
* @param {object} params
* @param {string} params.api_path - 接口路径,如 /user/GetProfile
* @param {string} params.method - HTTP 方法
* @param {object} params.query - query 参数(透传)
* @param {object} params.body - body 参数(透传)
* @param {object} params.headers - 需要透传的请求头
* @param {object} params.auth_ctx - 鉴权上下文verifyRequest 返回的 context
* @returns {object} { status, data, headers }
*/
async function forwardRequest({ api_path, method, query, body, headers, auth_ctx = {} }) {
const url = `${upstreamBaseUrl}${api_path}`;
const start = Date.now();
let status_code = 0;
let resp_data = null;
let resp_headers = {};
try {
const forwardHeaders = {};
if (headers["content-type"]) forwardHeaders["content-type"] = headers["content-type"];
if (headers["user-agent"]) forwardHeaders["user-agent"] = headers["user-agent"];
const resp = await axios({
method: method.toLowerCase(),
url,
params: query,
data: body,
headers: forwardHeaders,
timeout: 30000,
validateStatus: () => true,
});
status_code = resp.status;
resp_data = resp.data;
resp_headers = resp.headers;
} catch (err) {
status_code = 502;
resp_data = { ok: false, error_code: "UPSTREAM_ERROR", message: err.message };
logs.error(`[proxy] 转发失败 ${api_path}`, err.message);
}
const response_time = Date.now() - start;
// 异步写调用日志,不阻塞响应
writeCallLog({
user_id: auth_ctx.user_id,
token_id: auth_ctx.token_id,
api_path,
http_method: method.toUpperCase(),
status_code,
response_time,
response_body: serialize_response_for_log(resp_data),
}).catch((e) => logs.error("[proxy] 写调用日志失败", e.message));
return { status: status_code, data: resp_data, headers: resp_headers };
}
/**
* 写入 API 调用日志
*/
async function writeCallLog({
user_id,
token_id,
api_path,
http_method,
status_code,
response_time,
response_body,
}) {
try {
const now = new Date();
const call_date = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
await baseModel.biz_api_call_log.create({
user_id,
token_id,
api_path,
http_method,
status_code,
response_time,
response_body: response_body || null,
call_date,
created_at: now,
});
} catch (e) {
logs.error("[proxy] 写调用日志失败", e.message);
}
}
module.exports = { forwardRequest };