mirrorOf= 把私服请求拦去了公网镜像:本地能跑,CI 上内部包 404 排查

老炮踩坑录 · 番外篇 · 翻车现场系列

基于「基础企业档案」真实项目代码,复盘一次"本地构建正常、CI 上内部包 404"的排查

关键词:mirrorOf · settings.xml · 镜像 · !排除写法 · effective-settings

专业术语:CI(持续集成)

👋 欢迎阅读 🏠个人主页: 知守观

📘我的专栏: 老炮踩坑录

💻当前内容:Maven 镜像拦截规则

前言

上一篇《# 同事的 SNAPSHOT 更新了,我三天后才拉到》讲了 _remote.repositories 的来源校验。那篇的坑出在仓库 id 对不上,这篇的坑还是出在仓库 id 上------在 settings.xml 文件里一行 mirror 配置,匹配的对象就是仓库 id。

时间线接着上一篇:私服迁移完成,old-nexus 的账清干净了,新私服用了两周,一切正常。然后 CI 时却挂了。

现象:本地能跑,CI 上 404

周五下午,我提交了一版代码,CI 构建失败,报错信息如下:

text 复制代码
[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 贴出来:

xml 复制代码
<mirrors>
    <mirror>
        <id>alimaven</id>
        <name>aliyun maven</name>
        <url>https://maven.aliyun.com/repository/public</url>
        <mirrorOf>*</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 好久没人维护了,他找了篇博客抄了一份新的,博客作者配阿里云镜像是为了加速,用的 *。抄过来的时候,没人想到公司里还有个私服。

三个关键事实,分开讲。

  1. mirrorOf 匹配的是仓库 id,不是 URL。 很多人以为 * 匹配的是"所有地址",以为写个私服的 URL 就能绕开。不行,匹配的是 pom 和 settings 里 <repository> 的 id。想排除私服,得在 mirrorOf 里写它的 id:
xml 复制代码
<mirrorOf>*,!nexus</mirrorOf>

! 是排除写法,意思是"除了 id 为 nexus 的仓库,其他全部用镜像"。

  1. mirror 管不到 deploy。 同事的 deploy 走的是 distributionManagement,和 mirror 是两套配置,互不相干。所以这次事故里 deploy 一直成功、只有拉取 404,两边看起来矛盾,实际上各走各的路。

  2. 报错里的 id 和地址是镜像的。 请求被镜像接管之后,日志和报错里出现的就是镜像的 id 和 URL,原仓库的名字不会出现。排查时看到陌生的仓库 id,先别急着翻 pom,去 settings.xml 的 mirrors 里找。 mirrorOf 的完整写法,四种:

xml 复制代码
<mirrorOf>*</mirrorOf>                  <!-- 所有仓库 -->
<mirrorOf>central</mirrorOf>            <!-- 只接管 central -->
<mirrorOf>*,!nexus,!snapshots</mirrorOf> <!-- 全部,但排除 nexus 和 snapshots -->
<mirrorOf>external:*</mirrorOf>         <!-- 所有非本机的仓库(排除 localhost 和 file://) -->

修复

把 CI 的 settings.xml 改成显式排除私服:

xml 复制代码
<mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>https://maven.aliyun.com/repository/public</url>
    <mirrorOf>*,!nexus</mirrorOf>
</mirror>

改完重新构建,BUILD SUCCESS。

我倾向更保守的写法:只镜像 central,不用 *:

xml 复制代码
<mirrorOf>central</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 这东西,入职配一次,抄来的,之后几年不碰。它的内容很少有人逐行读过,可它对构建的控制权比 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老炮踩坑录」,看真实案例,少踩坑。

相关推荐
万物智能1 小时前
鸿蒙UART总线怎么用?—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
后端
UrbanJazzerati1 小时前
AutoHotkey v2 零基础快速入门 Part 5 游戏场景明暗阈值采集工具
后端
GoGeekBaird1 小时前
我做了一个给 Agent 用的电商开源项目:开店、上架、改版,跟 Agent 说一声就行
后端·github·agent
云和数据.ChenGuang1 小时前
Spring AI 对接 LangGraph:构建企业级智能体工作流实战
java·人工智能·spring boot·后端·spring
不老刘1 小时前
Maven 多医院分支场景下 groupId 的设计与 Jenkins 落地实践
servlet·jenkins·maven
woniu_maggie2 小时前
SAP 主数据 MDM 与MDG分析
后端
2 小时前
正则少一个 re.MULTILINE,我的安全闸门全程空转——而我以为修好了
后端·代码规范
柠檬味拥抱2 小时前
脑肿瘤检测数据集 | 4400张YOLO医学影像数据集
后端
柠檬味拥抱2 小时前
汽车损伤检测数据集 | 11700张YOLO车辆定损数据集
后端