优化版直接用
// ==UserScript==
// @name LD士多 | Trace Context CORS Fix
// @namespace ldc-cors-fix
// @version 2.0.0
// @description 临时移除 ldcstore.com API 请求中的 traceparent / tracestate,绕过后端 CORS 预检限制。
// @match https://ldcstore.com/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function () {
'use strict';
// =========================================================
// Configuration
// =========================================================
const CONFIG = {
// 是否输出调试日志
DEBUG: false,
// 需要移除的链路追踪请求头
STRIP_HEADERS: new Set([
'traceparent',
'tracestate'
]),
// 只处理这些 API 域名
// 如果后续 API 域名发生变化,可以在这里追加
API_HOSTS: new Set([
'api.ldspro.qzz.io',
'api1.ldspro.qzz.io',
'api2.ldspro.qzz.io'
])
};
const PREFIX = '[LDC CORS Fix]';
function log(...args) {
if (CONFIG.DEBUG) {
console.debug(PREFIX, ...args);
}
}
function warn(...args) {
console.warn(PREFIX, ...args);
}
function shouldHandleURL(input) {
try {
let url;
if (input instanceof Request) {
url = input.url;
} else {
url = String(input);
}
const parsed = new URL(url, location.href);
return CONFIG.API_HOSTS.has(parsed.hostname);
} catch {
return false;
}
}
function shouldStrip(name) {
return CONFIG.STRIP_HEADERS.has(
String(name).toLowerCase()
);
}
// =========================================================
// Headers Cleaner
// =========================================================
function cleanHeaders(headers) {
if (!headers) {
return headers;
}
try {
// ---------------------------------------------
// Headers instance
// ---------------------------------------------
if (
typeof Headers !== 'undefined' &&
headers instanceof Headers
) {
const cleaned = new Headers();
headers.forEach((value, name) => {
if (!shouldStrip(name)) {
cleaned.append(name, value);
} else {
log('Removed header:', name);
}
});
return cleaned;
}
// ---------------------------------------------
// Array format
// [
// ['Content-Type', 'application/json'],
// ['traceparent', '...']
// ]
// ---------------------------------------------
if (Array.isArray(headers)) {
return headers.filter(pair => {
if (!Array.isArray(pair) || pair.length < 2) {
return true;
}
const remove = shouldStrip(pair[0]);
if (remove) {
log('Removed header:', pair[0]);
}
return !remove;
});
}
// ---------------------------------------------
// Plain object
// {
// 'Content-Type': 'application/json',
// traceparent: '...'
// }
// ---------------------------------------------
if (
typeof headers === 'object' &&
headers !== null
) {
const cleaned = {};
Object.keys(headers).forEach(name => {
if (!shouldStrip(name)) {
cleaned[name] = headers[name];
} else {
log('Removed header:', name);
}
});
return cleaned;
}
} catch (error) {
warn('Failed to clean headers:', error);
}
return headers;
}
// =========================================================
// Request Cleaner
// =========================================================
function cleanRequest(request) {
try {
const headers = cleanHeaders(request.headers);
return new Request(request, {
headers
});
} catch (error) {
warn('Failed to rebuild Request:', error);
return request;
}
}
// =========================================================
// Fetch Hook
// =========================================================
const originalFetch = window.fetch;
if (!originalFetch) {
warn('window.fetch is unavailable.');
return;
}
if (originalFetch.__ldcCorsFixed) {
log('Fetch hook already installed.');
return;
}
const patchedFetch = function (input, init) {
try {
// -------------------------------------------------
// Request object
// -------------------------------------------------
if (input instanceof Request) {
if (shouldHandleURL(input)) {
const cleanedRequest = cleanRequest(input);
log(
'Patched Request:',
input.url
);
// 如果 init 也存在,则继续处理 init.headers
if (init && init.headers) {
init = {
...init,
headers: cleanHeaders(init.headers)
};
}
return originalFetch.call(
this,
cleanedRequest,
init
);
}
return originalFetch.call(
this,
input,
init
);
}
// -------------------------------------------------
// URL string
// -------------------------------------------------
if (shouldHandleURL(input)) {
if (init && init.headers) {
init = {
...init,
headers: cleanHeaders(init.headers)
};
log(
'Patched fetch:',
String(input)
);
}
return originalFetch.call(
this,
input,
init
);
}
} catch (error) {
// 不让补丁影响正常业务
warn('Fetch patch error:', error);
}
return originalFetch.call(
this,
input,
init
);
};
// 标记,防止重复 Hook
Object.defineProperty(
patchedFetch,
'__ldcCorsFixed',
{
value: true,
configurable: false,
enumerable: false
}
);
// 保留原 fetch 的部分属性
try {
Object.setPrototypeOf(
patchedFetch,
Object.getPrototypeOf(originalFetch)
);
} catch {}
window.fetch = patchedFetch;
// =========================================================
// XMLHttpRequest Hook
// =========================================================
//
// 如果新版前端未来部分接口从 fetch 改成 XHR,
// 这里也可以阻止 traceparent / tracestate。
//
// =========================================================
const originalSetRequestHeader =
XMLHttpRequest.prototype.setRequestHeader;
if (
originalSetRequestHeader &&
!originalSetRequestHeader.__ldcCorsFixed
) {
const patchedSetRequestHeader = function (
name,
value
) {
try {
if (shouldStrip(name)) {
// XHR 无法真正删除已经设置的 header,
// 所以这里直接阻止它被写入。
//
// 但只有在调用过程中我们无法知道 URL 时,
// 才存在潜在误伤。
//
// 因此这里只针对当前站点 API 请求。
const url = this.responseURL || this.__ldcRequestURL;
if (
url &&
shouldHandleURL(url)
) {
log(
'Blocked XHR header:',
name
);
return;
}
}
} catch (error) {
warn(
'XHR header patch error:',
error
);
}
return originalSetRequestHeader.call(
this,
name,
value
);
};
Object.defineProperty(
patchedSetRequestHeader,
'__ldcCorsFixed',
{
value: true,
configurable: false,
enumerable: false
}
);
XMLHttpRequest.prototype.setRequestHeader =
patchedSetRequestHeader;
}
// =========================================================
// XHR open hook
// =========================================================
//
// 保存 XHR 请求 URL,让 setRequestHeader 能判断
// 当前请求是否属于 ldcstore API。
//
// =========================================================
const originalOpen =
XMLHttpRequest.prototype.open;
if (
originalOpen &&
!originalOpen.__ldcCorsFixed
) {
const patchedOpen = function (
method,
url,
...rest
) {
try {
this.__ldcRequestURL = new URL(
url,
location.href
).href;
} catch {
this.__ldcRequestURL = String(url);
}
return originalOpen.call(
this,
method,
url,
...rest
);
};
Object.defineProperty(
patchedOpen,
'__ldcCorsFixed',
{
value: true,
configurable: false,
enumerable: false
}
);
XMLHttpRequest.prototype.open =
patchedOpen;
}
// =========================================================
// Ready
// =========================================================
log(
'Installed successfully.',
'Target API:',
[...CONFIG.API_HOSTS]
);
})();