Fix Docker deployment issues: add request.cf mock, boolean binding in SQLite, caches API mock, graceful purgeCFCache error handling

Co-authored-by: MarSeventh <[email protected]>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-03 16:46:40 +00:00
co-authored by MarSeventh
parent 5abd8bbe0f
commit 50e97d5d3d
4 changed files with 63 additions and 15 deletions
+21 -12
View File
@@ -6,19 +6,28 @@ let cfEmail = "";
let cfApiKey = "";
export async function purgeCFCache(env, cdnUrl) {
// 读取其他设置
othersConfig = await fetchOthersConfig(env);
cfZoneId = othersConfig.cloudflareApiToken.CF_ZONE_ID;
cfEmail = othersConfig.cloudflareApiToken.CF_EMAIL;
cfApiKey = othersConfig.cloudflareApiToken.CF_API_KEY;
try {
// 读取其他设置
othersConfig = await fetchOthersConfig(env);
cfZoneId = othersConfig.cloudflareApiToken.CF_ZONE_ID;
cfEmail = othersConfig.cloudflareApiToken.CF_EMAIL;
cfApiKey = othersConfig.cloudflareApiToken.CF_API_KEY;
// 清除CDN缓存
const options = {
method: 'POST',
headers: {'Content-Type': 'application/json', 'X-Auth-Email': `${cfEmail}`, 'X-Auth-Key': `${cfApiKey}`},
body: `{"files":["${ cdnUrl }"]}`
};
await fetch(`https://api.cloudflare.com/client/v4/zones/${ cfZoneId }/purge_cache`, options);
// 如果没有配置Cloudflare API,跳过缓存清除
if (!cfZoneId || !cfEmail || !cfApiKey) {
return;
}
// 清除CDN缓存
const options = {
method: 'POST',
headers: {'Content-Type': 'application/json', 'X-Auth-Email': `${cfEmail}`, 'X-Auth-Key': `${cfApiKey}`},
body: `{"files":["${ cdnUrl }"]}`
};
await fetch(`https://api.cloudflare.com/client/v4/zones/${ cfZoneId }/purge_cache`, options);
} catch (error) {
console.error('Failed to purge CF cache:', error.message || error);
}
}
export async function purgeRandomFileListCache(origin, ...dirs) {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "self-imgbed",
"name": "CloudFlare-ImgBed",
"lockfileVersion": 3,
"requires": true,
"packages": {
+35
View File
@@ -13,6 +13,19 @@ import { fileURLToPath } from 'url';
import { SqliteD1 } from './sqliteD1.js';
import { LocalR2Storage } from './r2Storage.js';
// ==================== 模拟 Cloudflare 全局 API ====================
// 模拟 Cloudflare Cache APINode.js 中不存在)
if (typeof globalThis.caches === 'undefined') {
globalThis.caches = {
default: {
async match() { return undefined; },
async put() {},
async delete() { return false; },
},
};
}
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT_DIR = resolve(__dirname, '..');
const FUNCTIONS_DIR = resolve(ROOT_DIR, 'functions');
@@ -211,6 +224,28 @@ async function handleFunctionRequest(request, pathname) {
middlewares.push(...mod.onRequest.slice(0, -1));
}
// 模拟 Cloudflare 的 request.cf 属性(telemetryData 等中间件依赖该属性)
if (!request.cf) {
request.cf = {
country: 'XX',
city: 'Unknown',
continent: 'XX',
latitude: '0',
longitude: '0',
region: '',
regionCode: '',
timezone: '',
postalCode: '',
asn: 0,
asOrganization: '',
colo: 'LOCAL',
httpProtocol: 'HTTP/1.1',
requestPriority: '',
tlsCipher: '',
tlsVersion: '',
};
}
// 创建 Cloudflare Pages Functions 风格的 context 对象
const env = createEnv();
const context = {
+6 -2
View File
@@ -41,8 +41,12 @@ class SqliteD1Statement {
* 绑定参数(模拟 D1 的 bind 方法)
*/
bind(...params) {
// SQLite 不支持 undefined,转换为 null 以兼容 D1 行为
this._params = params.map(p => p === undefined ? null : p);
// SQLite 不支持 undefined 和 boolean,转换以兼容 D1 行为
this._params = params.map(p => {
if (p === undefined) return null;
if (typeof p === 'boolean') return p ? 1 : 0;
return p;
});
return this;
}