LD士多 无法访问的原因,及解决办法

露帕 2026-08-22 10:32 1

站点 8 月 17 日后端迁移后,最新前端包内置了链路追踪,给每个 API 请求加 traceparent 头;但三个后端域名的 CORS 白名单(Content-Type, Authorization, X-Timestamp, X-Signature, X-Admin-Key)都没放行它,预检失败 → 所有浏览器里的 API 请求全部失败。商品列表、统计、登录链接接口都是这么挂的。


新版前端(index-BZQ97tYE.js 起)会给所有 API 请求注入 traceparent 头,
但 api/api1/api2.ldspro.qzz.io 的 CORS Access-Control-Allow-Headers
(Content-Type, Authorization, X-Timestamp, X-Signature, X-Admin-Key)没有
放行该头,预检失败导致所有浏览器端 API 请求挂掉(商品列表、统计、/api/auth/init 均
受影响)。修复方向:CORS 白名单加 traceparent/tracestate,或回滚前端追踪注入。



解决方法


在浏览器装个 Tampermonkey 扩展,新建脚本把文件内容贴进去保存即可。它在请求发出前剥掉 traceparent 头,站点数据立刻恢复正常。站方修好后删掉就行。


复制过来多了一堆转义符,看评论的新脚本吧
最新回复 (13)
  • vikey 08-22 10:32
    1

    刚想说咋访问不了呢 我还以为我梯子问题 换了几个都不行

  • 霜冻舞者 08-22 10:37
    2

    真难啊,太不容易了,终于可以进去了

  • relaxihg 08-22 10:40
    4

    好像还是不行呢,脚本不行了吗 ^-^

  • 第一个mt 08-22 10:41
    5

    用不了的注意把里面多余的"\"转义符删掉,大概有6个

  • Zhaozy666 08-22 10:42
    6

    (帖子已被作者删除)

  • Zhaozy666 08-22 10:43
    7

    (帖子已被作者删除)

  • Zhaozy666 08-22 10:43
    8

    这个是markdown格式复制粘贴导致的吗

  • Kisses 08-22 10:47
    9



    让gpt改了也用不了, 能发个懒人版吗 直接能用的

  • 露帕 楼主 08-22 10:55
    10
    // ==UserScript==
    // @name LD士多 traceparent CORS 修复
    // @namespace ldc-cors-fix
    // @version 1.0
    // @description ldcstore.com 新版前端给 API 请求注入 traceparent 头,后端 CORS 未放行导致所有请求失败。本脚本在浏览器侧移除该头,恢复站点数据加载。站方修复后可卸载。
    // @match https://ldcstore.com/*
    // @run-at document-start
    // @grant none
    // ==/UserScript==
    (function () {
    'use strict';
    var STRIP = /^(traceparent|tracestate)$/i;
    function cleanHeaders(h) {
    try {
    if (!h) return h;
    if (typeof Headers !== 'undefined' && h instanceof Headers) {
    var out = new Headers();
    h.forEach(function (v, k) { if (!STRIP.test(k)) out.set(k, v); });
    return out;
    }
    if (Array.isArray(h)) return h.filter(function (pair) { return !STRIP.test(pair[0]); });
    if (typeof h === 'object') {
    Object.keys(h).forEach(function (k) { if (STRIP.test(k)) delete h[k]; });
    return h;
    }
    } catch (e) { /* 出错时原样返回,不影响请求 */ }
    return h;
    }
    var origFetch = window.fetch;
    if (!origFetch || origFetch.__ldcCorsFixed) return;
    var wrapped = function (input, init) {
    if (init) init.headers = cleanHeaders(init.headers);
    return origFetch.call(this, input, init);
    };
    wrapped.__ldcCorsFixed = true;
    window.fetch = wrapped;
    })();
  • large_ppp 08-22 10:56
    11

    优化版直接用


    // ==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]
    );

    })();
  • 霜冻舞者 08-22 10:57
    12

    好多 @match 的也要弄掉。 哎辛苦。

  • relaxihg 08-22 11:00
    13

    感谢,成功下单了黑与白的邀请码 ^-^

  • tangxiaoyi 08-22 11:01
    14

    佬们,我进chrome却显示获取登录地址失败,但我换brave浏览器可以正常登录,这是浏览器版本的问题吗

* 帖子来源Linux.do
返回