)
老炮踩坑录 · 番外篇 · 翻车现场系列基于「基础企业档案」真实项目代码复盘一次本地构建正常、CI 上内部包 404的排查关键词mirrorOf · settings.xml · 镜像 · !排除写法 · effective-settings专业术语CI持续集成 欢迎阅读个人主页知守观我的专栏老炮踩坑录当前内容Maven 镜像拦截规则文章目录前言现象本地能跑CI 上 404排查先怀疑私服再怀疑 pom原因mirrorOf 匹配的是仓库 id\* 匹配所有修复这个坑为什么难排查自查清单老炮点评前言上一篇《Maven SNAPSHOT 更新排查》讲了_remote.repositories的来源校验。那篇的坑出在仓库 id 对不上这篇的坑还是出在仓库 id 上——在 settings.xml 文件里一行 mirror 配置匹配的对象就是仓库 id。时间线接着上一篇私服迁移完成old-nexus的账清干净了新私服用了两周一切正常。然后 CI 时却挂了。现象本地能跑CI 上 404周五下午我提交了一版代码CI 构建失败报错信息如下[ERROR] Failed to execute goal on project base-archives-web: Could not resolve dependencies for project cn.xiaomayi:base-archives-web:jar:0.0.1-SNAPSHOT: Could not find artifact cn.xiaomayi:base-archives-common:jar:0.0.1-SNAPSHOT in alimaven (https://maven.aliyun.com/repository/public) - [Help 1]base-archives-common是内部模块就在公司私服上上午同事还 deploy 过。我在本地把同样的代码拉下来同样的命令构建了一遍结果是 BUILD SUCCESS。同一份代码同一份 pom本地能下到的包CI 上却报 404错误。排查先怀疑私服再怀疑 pom第一个怀疑对象是私服本身。于是直接用浏览器访问了私服上 common 的目录jar 在时间戳是今天上午的说明私服没问题。第二个怀疑对象是 CI 的网络。让运维同事看了下CI 服务器网络也正常。然后我回头看报错。in alimaven (https://maven.aliyun.com/repository/public)这一段引起了我的注意alimaven 这个 id我们 pom 里没配过仓库地址是阿里云的公网镜像。一个公司内部的 groupId出现在公网镜像的报错里。公司内部包只存在于私服去阿里云找必然 404。问题变了CI 上的 Maven 为什么拿着内部包的坐标去公网镜像下载依赖让运维把 CI 服务器上的 settings.xml 贴出来mirrorsmirroridalimaven/idnamealiyun maven/nameurlhttps://maven.aliyun.com/repository/public/urlmirrorOf*/mirrorOf/mirror/mirrors报错里的 alimaven就是它。原因mirrorOf 匹配的是仓库 id* 匹配所有mirror 的工作方式Maven 发起仓库请求之前先过一遍 settings.xml 里的 mirror 列表看要访问的仓库 id 命中哪个 mirror 的mirrorOf规则。命中了这个请求就交给镜像处理——URL 换成镜像的地址id 换成镜像的 id原仓库不再出现。mirrorOf*的意思是接管所有仓库。私服 id 是nexus命中*于是下载cn.xiaomayi:base-archives-common的请求被换到了阿里云的地址。阿里云上没有这个包所以报 404错误。这份 settings.xml 是运维前一天换的。旧服务器的 settings.xml 好久没人维护了他找了篇博客抄了一份新的博客作者配阿里云镜像是为了加速用的*。抄过来的时候没人想到公司里还有个私服。三个关键事实分开讲。mirrorOf 匹配的是仓库 id不是 URL。很多人以为*匹配的是所有地址以为写个私服的 URL 就能绕开。不行匹配的是 pom 和 settings 里repository的 id。想排除私服得在 mirrorOf 里写它的 idmirrorOf*,!nexus/mirrorOf!是排除写法意思是除了 id 为 nexus 的仓库其他全部用镜像。mirror 管不到 deploy。同事的 deploy 走的是 distributionManagement和 mirror 是两套配置互不相干。所以这次事故里 deploy 一直成功、只有拉取 404两边看起来矛盾实际上各走各的路。报错里的 id 和地址是镜像的。请求被镜像接管之后日志和报错里出现的就是镜像的 id 和 URL原仓库的名字不会出现。排查时看到陌生的仓库 id先别急着翻 pom去 settings.xml 的 mirrors 里找。mirrorOf 的完整写法四种mirrorOf*/mirrorOf!-- 所有仓库 --mirrorOfcentral/mirrorOf!-- 只接管 central --mirrorOf*,!nexus,!snapshots/mirrorOf!-- 全部但排除 nexus 和 snapshots --mirrorOfexternal:*/mirrorOf!-- 所有非本机的仓库排除 localhost 和 file:// --有个细节我没完全确认mirrorOf* 在 Maven 3.6.x 和 3.9.x 上拦截行为有没有差异我本地验证的是 3.6.3其他版本没试过有踩过坑的兄弟评论区指点一下。修复把 CI 的 settings.xml 改成显式排除私服mirroridalimaven/idnamealiyun maven/nameurlhttps://maven.aliyun.com/repository/public/urlmirrorOf*,!nexus/mirrorOf/mirror改完重新构建BUILD SUCCESS。我倾向更保守的写法只镜像 central不用*mirrorOfcentral/mirrorOf中央仓库走阿里云加速其他仓库私服、jitpack、各种第三方仓库原样直连。镜像的范围越小意外接管的面就越小。还有一个连环坑也要提醒。如果 CI 的本地仓库是持久化的这次事故期间下载过的所有第三方依赖_remote.repositories里登记的都是alimaven。哪天把 mirror 整个撤了仓库 id 又对不上了——上一篇 F08 的坑会原样重现。撤 mirror 的时候要么保持镜像 id 不变要么清一次本地仓库。这个坑为什么难排查报错指向是歪的。看到Could not find artifact ... in alimaven第一反应是pom 里什么时候配了个阿里云翻完 pom 翻父 pom什么都找不到。镜像接管这个环节在日志里不露痕迹INFO 级别的输出里看不到请求被换地址这件事。本地和 CI 的配置差异藏得深。settings.xml 不在代码仓库里本地一份、CI 一份、每个同事一份改任何一份都没有记录可查。这次的事故现场CI 服务器和问题源头运维抄的配置之间还隔着一个人信息又多了一道衰减。*号这个写法流传太广。搜Maven 阿里云镜像前排文章清一色mirrorOf*抄的人默认它是标准配置。对纯开源依赖的项目它确实没问题一旦公司有私服它就是定时炸弹。自查清单自查打卡打开你的 settings.xml搜一下 mirrorOf把结果打在评论区——我看看谁的项目最“干净”。老炮点评settings.xml 这东西入职配一次抄来的之后几年不碰。它的内容很少有人逐行读过可它对构建的控制权比 pom 还大——pom 决定要什么settings 决定去哪拿后者改一行前者的所有配置都可能落空。本地能跑CI 却挂这类问题先 diff 环境再怀疑代码。这次我从 404 错误到定位绕的弯路全在怀疑私服、怀疑 pom上方向反了。最后问一句你有没有踩过被镜像接管的坑当时是怎么发现的评论区聊聊。延伸阅读前两篇番外篇讲了多模块没install和SNAPSHOT拉不到这篇讲mirrorOf把私服拦去公网。三篇构成了Maven仓库三部曲建议一起看下期预告《IDEA 里藏着的第二份 settings.xml》settings.xml 明明改对了命令行构建也正常了IDEA 里的依赖还是红的。翻遍设置才发现IDEA 的 Maven 配置里 override 了另一份 settings.xml路径指向一个两年前就不存在的目录。下期讲 IDEA 和命令行各用各的配置时怎么让它们说同一种话。如果本文对你有帮助欢迎 点赞 ⭐ 收藏 关注 留言我是老炮Java 老兵仍在一线。关注「Java老炮踩坑录」看真实案例少踩坑。