vr-shopxo-plugin/docs/DEBUG_STATIC_FILE_SYNC.md

5.5 KiB
Raw Blame History

ShopXO 插件静态文件同步陷阱

2026-04-24 票夹 API 请求 404 根因分析

关键词ShopXO、插件静态文件、public/ vs app/、Nginx root、docker cp、双目录陷阱


现象

票夹页面加载正常,但所有 API 请求返回 404

curl http://localhost:10000/plugins/vr_ticket//api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=list
→ 404

浏览器 Network 面板显示 JS 正在请求 /plugins/vr_ticket//api.php(双斜杠),但该路径不存在。


根因ShopXO 插件静态文件有两套副本

ShopXO 插件文件在容器内存在于两个位置:

路径 用途 Nginx 是否 serve
/var/www/html/app/plugins/vr_ticket/ PHP 运行时源码 PHP 代码目录
/var/www/html/public/plugins/vr_ticket/ Nginx webroot 静态副本 Nginx 直接 serve

Nginx 的 root 指令是 /var/www/html/public,因此所有浏览器请求的 URL 路径 /plugins/vr_ticket/static/js/xxx.js 都会被 Nginx 从 public/plugins/ 目录读取。

PHPThinkPHP运行时加载插件类文件时使用 app/plugins/ 目录。

为什么会产生两份不同的文件?

正常情况bind mount:如果 app/public/ 都是同一个 bind mount 的子目录(/var/www/html → host 的 shopxo 目录),它们应该是同一个源。

异常情况当手动在容器内修改文件、Docker cp 上传文件、或者插件重装时,这两个目录可能产生分歧:

  1. docker cp 直接写入容器路径 → 如果写入 app/public/ 是镜像层预置,则不同步
  2. 插件重装时 ShopXO 同步静态文件到 public/ 但没有同步 app/
  3. 容器内手动编辑 public/ 后没有更新 app/

验证方法

# 对比两边的 MD5不一致 = 有问题)
docker exec shopxo-php md5sum \
  /var/www/html/app/plugins/vr_ticket/static/js/ticket_card.js \
  /var/www/html/public/plugins/vr_ticket/static/js/ticket_card.js

# 如果 MD5 不同,需要手动同步
docker cp /path/to/local/file.js \
  shopxo-php:/var/www/html/public/plugins/vr_ticket/static/js/file.js

# 同时也要更新 app/(运行时需要)
docker cp /path/to/local/file.js \
  shopxo-php:/var/www/html/app/plugins/vr_ticket/static/js/file.js

本次 Caseticket_card.js 的 apiBase 构造错误

问题代码ticket_card.js

var apiBase = document.currentScript ? 
    document.currentScript.src.replace(/static\/js\/[^/]+$/, '') + '/api.php?...':
    '/api.php?...';

当脚本被加载为 /plugins/vr_ticket/static/js/ticket_card.js 时:

  • document.currentScript.src = http://localhost:10000/plugins/vr_ticket/static/js/ticket_card.js
  • replace(/static\/js\/[^/]+$/, '') = http://localhost:10000/plugins/vr_ticket/
  • 拼接 /api.php?...http://localhost:10000/plugins/vr_ticket/api.php?...双斜杠404

修复方案

硬编码 apiBase 为绝对路径,绕过动态检测:

var apiBase = '/api.php?s=plugins/index&pluginsname=vr_ticket&pluginscontrol=ticket&pluginsaction=';

为什么之前修错了位置?

docker cp 更新了 app/plugins/vr_ticket/static/js/ticket_card.js,但浏览器被 Nginx serve 的是 public/plugins/vr_ticket/static/js/ticket_card.js(旧版)。直到把修复也同步到 public/ 后才生效。


经验总结

修改插件静态文件的标准流程

  1. 同时修改 app/public/ 两个副本

    # 方式A先改源码再同步副本
    vim app/plugins/vr_ticket/static/js/xxx.js
    cp app/plugins/vr_ticket/static/js/xxx.js public/plugins/vr_ticket/static/js/xxx.js
    
    # 方式B直接用 docker cp 同步到两边
    docker cp local.js shopxo-php:/var/www/html/app/plugins/vr_ticket/static/js/xxx.js
    docker cp local.js shopxo-php:/var/www/html/public/plugins/vr_ticket/static/js/xxx.js
    
  2. 修改后立即验证 MD5

    docker exec shopxo-php md5sum \
      /var/www/html/app/plugins/vr_ticket/static/js/xxx.js \
      /var/www/html/public/plugins/vr_ticket/static/js/xxx.js
    # 两个 MD5 必须一致
    
  3. 如果用了 ThinkPHP 模板缓存,清理模板编译缓存:

    docker exec shopxo-php find /var/www/html/runtime/index/temp -name "*.php" -delete
    docker exec shopxo-php find /var/www/html/runtime/cache/shopxo -name "*.php" -delete
    

ShopXO 静态文件分布图

宿主机bind mount 源)
  /Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/
    ├── app/plugins/vr_ticket/         ← PHP 运行时读取
    │   └── static/js/ticket_card.js
    └── public/plugins/vr_ticket/      ← Nginx webroot浏览器访问
        └── static/js/ticket_card.js
              ↓ bind mount
容器 /var/www/html/
    ├── app/plugins/vr_ticket/         ← PHP runtime
    └── public/plugins/vr_ticket/     ← Nginx root

预防措施

  • 不要在容器内直接修改文件(用 docker cpapp/ 后手动复制到 public/
  • 插件重装后立即检查两边 MD5
  • 如果 bind mount 正常,两边应该永远同步;如果不同步,检查是否有额外的 Docker 镜像层覆盖了 public/

相关文档