Files
web_huangguo_web/app/static/js/common/request.js
T
fish03andClaude Opus 5.5 bef9f8b4ed Initial commit
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 14:43:16 +07:00

143 lines
5.0 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.
/**
* 前端请求封装。
* - 登录态走 cookie(credentials: include)
* - 浏览器无法改写 User-Agent;X-Real-IP 由服务端反代上游时注入
* - 直连上游时若需自定义头,请走本站 Go 代理接口
*/
(function (global) {
var DEFAULT_TIMEOUT_MS = 30000;
function buildQuery(params) {
if (!params) return "";
var pairs = [];
Object.keys(params).forEach(function (key) {
var value = params[key];
if (value == null) return;
pairs.push(encodeURIComponent(key) + "=" + encodeURIComponent(String(value)));
});
return pairs.length ? "?" + pairs.join("&") : "";
}
/**
* @param {string} url
* @param {{
* method?: string,
* data?: any,
* params?: Record<string, any>,
* headers?: Record<string, string>,
* timeout?: number,
* }} [options]
*/
function request(url, options) {
options = options || {};
var method = String(options.method || "GET").toUpperCase();
var headers = Object.assign(
{ Accept: "application/json" },
options.headers || {}
);
var finalUrl = url + buildQuery(options.params);
var body;
var controller = typeof AbortController !== "undefined" ? new AbortController() : null;
var timer;
if (options.data != null && method !== "GET" && method !== "HEAD") {
if (typeof FormData !== "undefined" && options.data instanceof FormData) {
body = options.data;
} else {
headers["Content-Type"] = headers["Content-Type"] || "application/json";
body =
headers["Content-Type"].indexOf("application/json") >= 0
? JSON.stringify(options.data)
: options.data;
}
}
var fetchOpts = {
method: method,
headers: headers,
credentials: "include",
signal: controller ? controller.signal : undefined,
};
if (body != null) fetchOpts.body = body;
var timeoutMs =
typeof options.timeout === "number" ? options.timeout : DEFAULT_TIMEOUT_MS;
if (controller && timeoutMs > 0) {
timer = setTimeout(function () {
controller.abort();
}, timeoutMs);
}
return fetch(finalUrl, fetchOpts)
.then(function (res) {
var contentType = res.headers.get("content-type") || "";
var parse = contentType.indexOf("application/json") >= 0
? res.json()
: res.text();
return parse.then(function (data) {
if (!res.ok) {
var err = new Error(
(data && data.msg) || (data && data.message) || res.statusText || "request failed"
);
err.status = res.status;
err.code = data && data.code;
err.data = data;
throw err;
}
return data;
});
})
.then(function (data) {
return handleTokenExpiredResponse(url, options, data);
})
.finally(function () {
if (timer) clearTimeout(timer);
});
}
/**
* 业务码 1000:token 失效。
* 游客 → 重新游客登录并重试一次;注册账号 → 打开登录弹窗/跳转登录页。
*/
function handleTokenExpiredResponse(url, options, data) {
options = options || {};
var expiredCode =
(global.AuthAPI && global.AuthAPI.TOKEN_EXPIRED_CODE) || 1000;
if (!data || Number(data.code) !== Number(expiredCode)) {
return data;
}
if (options._skipTokenRecovery || options._tokenRetried) {
return data;
}
if (
global.AuthAPI &&
typeof global.AuthAPI.isAuthEndpoint === "function" &&
global.AuthAPI.isAuthEndpoint(url)
) {
return data;
}
if (!global.AuthAPI || typeof global.AuthAPI.handleTokenExpired !== "function") {
return data;
}
return global.AuthAPI.handleTokenExpired().then(function (result) {
if (result && result.ok && result.guest) {
return request(
url,
Object.assign({}, options, { _tokenRetried: true })
);
}
return data;
});
}
global.HttpRequest = {
request: request,
get: function (url, options) {
return request(url, Object.assign({}, options, { method: "GET" }));
},
post: function (url, data, options) {
return request(url, Object.assign({}, options, { method: "POST", data: data }));
},
};
})(typeof window !== "undefined" ? window : this);