feat: api fetch timeout

This commit is contained in:
Gabe
2025-07-01 12:38:06 +08:00
parent 30129abef3
commit 97b4935bc4
4 changed files with 64 additions and 21 deletions

View File

@@ -40,7 +40,12 @@ export const CLIENT_EDGE = "edge";
export const CLIENT_FIREFOX = "firefox"; export const CLIENT_FIREFOX = "firefox";
export const CLIENT_USERSCRIPT = "userscript"; export const CLIENT_USERSCRIPT = "userscript";
export const CLIENT_THUNDERBIRD = "thunderbird"; export const CLIENT_THUNDERBIRD = "thunderbird";
export const CLIENT_EXTS = [CLIENT_CHROME, CLIENT_EDGE, CLIENT_FIREFOX, CLIENT_THUNDERBIRD]; export const CLIENT_EXTS = [
CLIENT_CHROME,
CLIENT_EDGE,
CLIENT_FIREFOX,
CLIENT_THUNDERBIRD,
];
export const KV_RULES_KEY = "kiss-rules.json"; export const KV_RULES_KEY = "kiss-rules.json";
export const KV_WORDS_KEY = "kiss-words.json"; export const KV_WORDS_KEY = "kiss-words.json";
@@ -101,7 +106,8 @@ export const URL_BAIDU_TRANSAPI = "https://fanyi.baidu.com/transapi";
export const URL_BAIDU_TRANSAPI_V2 = "https://fanyi.baidu.com/v2transapi"; export const URL_BAIDU_TRANSAPI_V2 = "https://fanyi.baidu.com/v2transapi";
export const URL_DEEPLFREE_TRAN = "https://www2.deepl.com/jsonrpc"; export const URL_DEEPLFREE_TRAN = "https://www2.deepl.com/jsonrpc";
export const URL_TENCENT_TRANSMART = "https://transmart.qq.com/api/imt"; export const URL_TENCENT_TRANSMART = "https://transmart.qq.com/api/imt";
export const URL_VOLCENGINE_TRAN = "https://translate.volcengine.com/crx/translate/v1"; export const URL_VOLCENGINE_TRAN =
"https://translate.volcengine.com/crx/translate/v1";
export const URL_NIUTRANS_REG = export const URL_NIUTRANS_REG =
"https://niutrans.com/login?active=3&userSource=kiss-translator"; "https://niutrans.com/login?active=3&userSource=kiss-translator";
@@ -530,6 +536,8 @@ export const DEFAULT_SUBRULES_LIST = [
}, },
]; ];
export const DEFAULT_HTTP_TIMEOUT = 5000; // 调用超时时间
// 翻译接口 // 翻译接口
const defaultCustomApi = { const defaultCustomApi = {
url: "", url: "",
@@ -539,6 +547,9 @@ const defaultCustomApi = {
resHook: "", // response 钩子函数 resHook: "", // response 钩子函数
fetchLimit: DEFAULT_FETCH_LIMIT, fetchLimit: DEFAULT_FETCH_LIMIT,
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
apiName: "",
isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}; };
const defaultOpenaiApi = { const defaultOpenaiApi = {
url: "https://api.openai.com/v1/chat/completions", url: "https://api.openai.com/v1/chat/completions",
@@ -552,6 +563,7 @@ const defaultOpenaiApi = {
fetchInterval: 500, fetchInterval: 500,
apiName: "", apiName: "",
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
}; };
const defaultOllamaApi = { const defaultOllamaApi = {
url: "http://localhost:11434/api/generate", url: "http://localhost:11434/api/generate",
@@ -565,6 +577,7 @@ const defaultOllamaApi = {
fetchInterval: 500, fetchInterval: 500,
apiName: "", apiName: "",
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
}; };
export const DEFAULT_TRANS_APIS = { export const DEFAULT_TRANS_APIS = {
[OPT_TRANS_GOOGLE]: { [OPT_TRANS_GOOGLE]: {
@@ -572,8 +585,9 @@ export const DEFAULT_TRANS_APIS = {
key: "", key: "",
fetchLimit: DEFAULT_FETCH_LIMIT, // 最大任务数量 fetchLimit: DEFAULT_FETCH_LIMIT, // 最大任务数量
fetchInterval: DEFAULT_FETCH_INTERVAL, // 任务间隔时间 fetchInterval: DEFAULT_FETCH_INTERVAL, // 任务间隔时间
apiName: OPT_TRANS_GOOGLE, apiName: OPT_TRANS_GOOGLE, // 接口自定义名称
isDisabled: false, isDisabled: false, // 是否禁用
httpTimeout: DEFAULT_HTTP_TIMEOUT, // 超时时间
}, },
[OPT_TRANS_GOOGLE2]: { [OPT_TRANS_GOOGLE2]: {
url: URL_GOOGLE_TRAN2, url: URL_GOOGLE_TRAN2,
@@ -582,30 +596,35 @@ export const DEFAULT_TRANS_APIS = {
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
apiName: OPT_TRANS_GOOGLE2, apiName: OPT_TRANS_GOOGLE2,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_MICROSOFT]: { [OPT_TRANS_MICROSOFT]: {
fetchLimit: DEFAULT_FETCH_LIMIT, fetchLimit: DEFAULT_FETCH_LIMIT,
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
apiName: OPT_TRANS_MICROSOFT, apiName: OPT_TRANS_MICROSOFT,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_BAIDU]: { [OPT_TRANS_BAIDU]: {
fetchLimit: DEFAULT_FETCH_LIMIT, fetchLimit: DEFAULT_FETCH_LIMIT,
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
apiName: OPT_TRANS_BAIDU, apiName: OPT_TRANS_BAIDU,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_TENCENT]: { [OPT_TRANS_TENCENT]: {
fetchLimit: DEFAULT_FETCH_LIMIT, fetchLimit: DEFAULT_FETCH_LIMIT,
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
apiName: OPT_TRANS_TENCENT, apiName: OPT_TRANS_TENCENT,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_VOLCENGINE]: { [OPT_TRANS_VOLCENGINE]: {
fetchLimit: DEFAULT_FETCH_LIMIT, fetchLimit: DEFAULT_FETCH_LIMIT,
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
apiName: OPT_TRANS_VOLCENGINE, apiName: OPT_TRANS_VOLCENGINE,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_DEEPL]: { [OPT_TRANS_DEEPL]: {
url: "https://api-free.deepl.com/v2/translate", url: "https://api-free.deepl.com/v2/translate",
@@ -614,12 +633,14 @@ export const DEFAULT_TRANS_APIS = {
fetchInterval: 500, fetchInterval: 500,
apiName: OPT_TRANS_DEEPL, apiName: OPT_TRANS_DEEPL,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_DEEPLFREE]: { [OPT_TRANS_DEEPLFREE]: {
fetchLimit: 1, fetchLimit: 1,
fetchInterval: 500, fetchInterval: 500,
apiName: OPT_TRANS_DEEPLFREE, apiName: OPT_TRANS_DEEPLFREE,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_DEEPLX]: { [OPT_TRANS_DEEPLX]: {
url: "http://localhost:1188/translate", url: "http://localhost:1188/translate",
@@ -628,6 +649,7 @@ export const DEFAULT_TRANS_APIS = {
fetchInterval: 500, fetchInterval: 500,
apiName: OPT_TRANS_DEEPLX, apiName: OPT_TRANS_DEEPLX,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_NIUTRANS]: { [OPT_TRANS_NIUTRANS]: {
url: "https://api.niutrans.com/NiuTransServer/translation", url: "https://api.niutrans.com/NiuTransServer/translation",
@@ -638,6 +660,7 @@ export const DEFAULT_TRANS_APIS = {
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
apiName: OPT_TRANS_NIUTRANS, apiName: OPT_TRANS_NIUTRANS,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT,
}, },
[OPT_TRANS_OPENAI]: defaultOpenaiApi, [OPT_TRANS_OPENAI]: defaultOpenaiApi,
[OPT_TRANS_OPENAI_2]: defaultOpenaiApi, [OPT_TRANS_OPENAI_2]: defaultOpenaiApi,
@@ -652,6 +675,7 @@ export const DEFAULT_TRANS_APIS = {
fetchInterval: 500, fetchInterval: 500,
apiName: OPT_TRANS_GEMINI, apiName: OPT_TRANS_GEMINI,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
}, },
[OPT_TRANS_CLAUDE]: { [OPT_TRANS_CLAUDE]: {
url: "https://api.anthropic.com/v1/messages", url: "https://api.anthropic.com/v1/messages",
@@ -665,6 +689,7 @@ export const DEFAULT_TRANS_APIS = {
fetchInterval: 500, fetchInterval: 500,
apiName: OPT_TRANS_CLAUDE, apiName: OPT_TRANS_CLAUDE,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
}, },
[OPT_TRANS_CLOUDFLAREAI]: { [OPT_TRANS_CLOUDFLAREAI]: {
url: "https://api.cloudflare.com/client/v4/accounts/{{ACCOUNT_ID}}/ai/run/@cf/meta/m2m100-1.2b", url: "https://api.cloudflare.com/client/v4/accounts/{{ACCOUNT_ID}}/ai/run/@cf/meta/m2m100-1.2b",
@@ -673,6 +698,7 @@ export const DEFAULT_TRANS_APIS = {
fetchInterval: 500, fetchInterval: 500,
apiName: OPT_TRANS_CLOUDFLAREAI, apiName: OPT_TRANS_CLOUDFLAREAI,
isDisabled: false, isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
}, },
[OPT_TRANS_OLLAMA]: defaultOllamaApi, [OPT_TRANS_OLLAMA]: defaultOllamaApi,
[OPT_TRANS_OLLAMA_2]: defaultOllamaApi, [OPT_TRANS_OLLAMA_2]: defaultOllamaApi,
@@ -699,7 +725,6 @@ export const DEFAULT_SHORTCUTS = {
export const TRANS_MIN_LENGTH = 5; // 最短翻译长度 export const TRANS_MIN_LENGTH = 5; // 最短翻译长度
export const TRANS_MAX_LENGTH = 5000; // 最长翻译长度 export const TRANS_MAX_LENGTH = 5000; // 最长翻译长度
export const TRANS_NEWLINE_LENGTH = 20; // 换行字符数 export const TRANS_NEWLINE_LENGTH = 20; // 换行字符数
export const HTTP_TIMEOUT = 5000; // 调用超时时间
export const DEFAULT_BLACKLIST = [ export const DEFAULT_BLACKLIST = [
"https://fishjar.github.io/kiss-translator/options.html", "https://fishjar.github.io/kiss-translator/options.html",
"https://translate.google.com", "https://translate.google.com",
@@ -717,7 +742,7 @@ export const DEFAULT_SETTING = {
minLength: TRANS_MIN_LENGTH, minLength: TRANS_MIN_LENGTH,
maxLength: TRANS_MAX_LENGTH, maxLength: TRANS_MAX_LENGTH,
newlineLength: TRANS_NEWLINE_LENGTH, newlineLength: TRANS_NEWLINE_LENGTH,
httpTimeout: HTTP_TIMEOUT, httpTimeout: DEFAULT_HTTP_TIMEOUT,
clearCache: false, // 是否在浏览器下次启动时清除缓存 clearCache: false, // 是否在浏览器下次启动时清除缓存
injectRules: true, // 是否注入订阅规则 injectRules: true, // 是否注入订阅规则
// injectWebfix: true, // 是否注入修复补丁(作废) // injectWebfix: true, // 是否注入修复补丁(作废)

View File

@@ -9,7 +9,7 @@ import {
CACHE_NAME, CACHE_NAME,
DEFAULT_FETCH_INTERVAL, DEFAULT_FETCH_INTERVAL,
DEFAULT_FETCH_LIMIT, DEFAULT_FETCH_LIMIT,
HTTP_TIMEOUT, DEFAULT_HTTP_TIMEOUT,
} from "../config"; } from "../config";
import { isBg } from "./browser"; import { isBg } from "./browser";
import { genTransReq } from "../apis/trans"; import { genTransReq } from "../apis/trans";
@@ -40,7 +40,10 @@ const newCacheReq = async (input, init) => {
* @param {*} init * @param {*} init
* @returns * @returns
*/ */
export const fetchGM = async (input, { method = "GET", headers, body, timeout = HTTP_TIMEOUT } = {}) => export const fetchGM = async (
input,
{ method = "GET", headers, body, timeout } = {}
) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
GM.xmlHttpRequest({ GM.xmlHttpRequest({
method, method,
@@ -82,13 +85,14 @@ export const fetchPatcher = async (input, init, transOpts, apiSetting) => {
throw new Error("url is empty"); throw new Error("url is empty");
} }
let timeout = HTTP_TIMEOUT; let timeout = apiSetting?.httpTimeout || DEFAULT_HTTP_TIMEOUT;
if (!apiSetting) {
try { try {
// todo: 不必每次都查询,缓存参数
timeout = (await getSettingWithDefault()).httpTimeout; timeout = (await getSettingWithDefault()).httpTimeout;
} catch (err) { } catch (err) {
// //
} }
}
if (isGm) { if (isGm) {
let info; let info;

View File

@@ -29,6 +29,7 @@ import {
URL_NIUTRANS_REG, URL_NIUTRANS_REG,
DEFAULT_FETCH_LIMIT, DEFAULT_FETCH_LIMIT,
DEFAULT_FETCH_INTERVAL, DEFAULT_FETCH_INTERVAL,
DEFAULT_HTTP_TIMEOUT,
} from "../../config"; } from "../../config";
import { useState } from "react"; import { useState } from "react";
import { useI18n } from "../../hooks/I18n"; import { useI18n } from "../../hooks/I18n";
@@ -125,6 +126,7 @@ function ApiFields({ translator }) {
thinkIgnore = "", thinkIgnore = "",
fetchLimit = DEFAULT_FETCH_LIMIT, fetchLimit = DEFAULT_FETCH_LIMIT,
fetchInterval = DEFAULT_FETCH_INTERVAL, fetchInterval = DEFAULT_FETCH_INTERVAL,
httpTimeout = DEFAULT_HTTP_TIMEOUT,
dictNo = "", dictNo = "",
memoryNo = "", memoryNo = "",
reqHook = "", reqHook = "",
@@ -144,6 +146,9 @@ function ApiFields({ translator }) {
case "fetchInterval": case "fetchInterval":
value = limitNumber(value, 0, 5000); value = limitNumber(value, 0, 5000);
break; break;
case "httpTimeout":
value = limitNumber(value, 5000, 30000);
break;
case "temperature": case "temperature":
value = limitFloat(value, 0, 2); value = limitFloat(value, 0, 2);
break; break;
@@ -263,7 +268,7 @@ function ApiFields({ translator }) {
</> </>
)} )}
{(translator.startsWith(OPT_TRANS_OLLAMA)) && ( {translator.startsWith(OPT_TRANS_OLLAMA) && (
<> <>
<TextField <TextField
select select
@@ -368,6 +373,15 @@ function ApiFields({ translator }) {
onChange={handleChange} onChange={handleChange}
/> />
<TextField
size="small"
label={i18n("http_timeout")}
type="number"
name="httpTimeout"
defaultValue={httpTimeout}
onChange={handleChange}
/>
<FormControlLabel <FormControlLabel
control={ control={
<Switch <Switch

View File

@@ -27,7 +27,7 @@ import {
DEFAULT_CSPLIST, DEFAULT_CSPLIST,
MSG_CONTEXT_MENUS, MSG_CONTEXT_MENUS,
MSG_UPDATE_CSP, MSG_UPDATE_CSP,
HTTP_TIMEOUT, DEFAULT_HTTP_TIMEOUT,
} from "../../config"; } from "../../config";
import { useShortcut } from "../../hooks/Shortcut"; import { useShortcut } from "../../hooks/Shortcut";
import ShortcutInput from "./ShortcutInput"; import ShortcutInput from "./ShortcutInput";
@@ -114,7 +114,7 @@ export default function Settings() {
maxLength, maxLength,
clearCache, clearCache,
newlineLength = TRANS_NEWLINE_LENGTH, newlineLength = TRANS_NEWLINE_LENGTH,
httpTimeout = HTTP_TIMEOUT, httpTimeout = DEFAULT_HTTP_TIMEOUT,
contextMenuType = 1, contextMenuType = 1,
touchTranslate = 2, touchTranslate = 2,
blacklist = DEFAULT_BLACKLIST.join(",\n"), blacklist = DEFAULT_BLACKLIST.join(",\n"),