ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Maven报错Blocked mirror for repositories?一文搞懂原因与五种解决方法

Maven报错Blocked mirror for repositories?一文搞懂原因与五种解决方法 做Java后端的基本天天跟Maven打交道依赖拉不下来这种报错见得多了但Blocked mirror for repositories这个提示第一次遇到还是挺懵的。它不像普通的404或者网络超时那么直白翻译过来是镜像被阻止了可明明settings.xml里配置得好好的为什么就被blocked了呢这篇内容从我实际排查这个Maven依赖解析失败问题的完整过程出发把问题原因、机制原理以及几种有效的解决方式一次性讲清楚希望你在IDEA和命令行里遇到同样报错时能少走点弯路。1. 先看现场Blocked mirror for repositories 到底长什么样1.1 命令行里的完整报错长这样我们先看一段我在本地真实遇到的错误日志当时执行的是mvn clean install项目非常简单只依赖了一个guava[ERROR] Failed to execute goal on project demo: Could not resolve dependencies for project com.example:demo:jar:1.0-SNAPSHOT: Failed to collect dependencies at com.google.guava:guava:30.1-jre:pom:30.1-jre: Failed to read artifact descriptor for com.google.guava:guava:30.1-jre: Could not transfer artifact com.google.guava:guava:30.1-jre:pom:30.1-jre from/to central (http://repo.maven.apache.org/maven2): Blocked mirror for repositories: [central (http://repo.maven.apache.org/maven2, default, releasessnapshots)]这段日志里有个关键线索末尾的Blocked mirror for repositories后面清清楚楚地标出了仓库地址http://repo.maven.apache.org/maven2——请注意它是http://不是https://。我当时的第一个反应是去检查网络通不通结果curl http://repo.maven.apache.org/maven2完全正常域名能访问、页面能打开。这就很诡异了地址能访问但Maven自己却拒绝下载。后来我才意识到问题根本不在网络而是Maven在配置层面就拒收了这个HTTP地址的依赖请求。1.2 IDEA 里的表现与最典型触发特征如果你是在IDEA里遇到这个问题表现会稍微不一样。常见的场景是右侧Maven工具窗口刷新项目时直接弹出红色的错误提示Event Log里写着Unable to import Maven project: Blocked mirror for repositories: [central (...)]然后整个pom.xml的第一行就飘红所有依赖全部无法解析。这种情况最容易在满足下面几个条件的机器上出现Maven版本是3.8.1或更高我用的是3.9.x。全局或用户级settings.xml里的镜像地址还是老的HTTP格式比如http://maven.aliyun.com/nexus/content/groups/public。或者pom.xml里手动声明了某个repository它的URL以http://开头。使用IDEA自带的Bundled Maven时更容易触发因为IDEA内置的Maven版本往往跟随新版本发布默认配置会带上这类安全校验。我随手跟同事聊了一下发现踩这个坑的不止我一个。尤其是那些从网上找了一份老配置、直接把settings.xml复制进~/.m2目录的同事几乎全军覆没。下面我先把原理讲清楚再给解决方案不然改了配置也不知道为什么能好。2. 别再乱改了先搞懂 Maven 为什么会拦截 HTTP 仓库2.1 用快递中转站理解 Maven 镜像先说个基础概念方便还没太搞明白镜像机制的朋友。你把Maven想象成代购你告诉它我要依赖com.google.guava:guava:30.1-jre它默认会去美国的Maven中央仓库取货。但中央仓库在国外网络慢于是我们配置了镜像——相当于在国内找一个中转站。你在settings.xml里写的mirror就是中转站的地址Maven先去中转站取货取不到再考虑原始仓库。这个机制想法很好但也很容易出问题。一旦中转站配置不对或者原始仓库本身不受信任整个流程就会卡住。这次的Blocked mirror就属于后者不是中转站坏了而是Maven认为目标仓库不该走HTTP。2.2 官方默认加了一把安全锁从Maven 3.8.1开始官方在默认的settings.xml里专门加了一个拦截配置代码长这样mirror idmaven-default-http-blocker/id mirrorOfexternal:http:*/mirrorOf namePseudo repository to mirror external repositories initially using HTTP./name urlhttp://0.0.0.0//url blockedtrue/blocked /mirror这段配置的作用通俗地说就是凡是通过HTTP协议访问的外部仓库Maven一律视为不安全的访问来源统一标记为blockedtrue直接拒绝下载。external:http:*这个表达式拆开来解释external:表示这个仓库不在本机范围内也就是不属于localhost、127.0.0.1或者file://协议的本地路径。http:表示协议是HTTP明文传输。*当然是通配符表示所有外部HTTP地址全部命中。所以只要你项目的pom.xml里有任意一个仓库URL是http://或者你配置的镜像地址本身是http://Maven就会认为你试图访问一个不安全的仓库然后把请求拦下来抛出的正是我们看到的Blocked mirror for repositories。2.3 为什么官方宁可误伤也不放过不少开发者的第一反应是Maven是不是抽风了老仓库地址用了多少年都没问题。其实Maven官方这么做是有明确安全考虑的。HTTP协议传输的数据是明文从中央仓库下载的jar包如果被中间人篡改恶意代码就会悄无声息进入我们的本地仓库和最终构建产物里这是非常典型的供应链攻击路径。Maven社区从2014年就一直在推动全面HTTPS化中央仓库本身在2014年就切换到了HTTPS地址。到了3.8.1版本官方终于下了狠心直接默认在配置层面加上拦截器用一刀切的方式强制所有HTTP外部仓库停用。这就是为什么我们升级Maven版本之后老的HTTP镜像一夜之间全部失效。理解了这个机制之后你会发现自己遇到的所有Blocked mirror问题都可以归结为两类要么是镜像地址用了HTTP要么是项目声明的仓库地址用了HTTP。解决方案自然也有了明确方向。3. 亲测有效的五种解决思路按推荐程度排序3.1 方案一把镜像地址升级成 HTTPS首选最推荐的方案就是检查settings.xml里所有镜像和仓库地址把http://统统换成https://。国内使用阿里云镜像的特别多这里特别注意一点阿里云仓库的旧地址和新地址不只是协议变了域名和路径也变了。旧地址HTTP会被Blockedhttp://maven.aliyun.com/nexus/content/groups/public新地址HTTPS推荐https://maven.aliyun.com/repository/public很多人在网上找到的老教程里写的还是旧地址直接复制就踩了坑。我实测下来新版阿里云地址稳定性和速度都更好推荐直接迁移。如果你用的是其它国内镜像站也尽量选HTTPS版本腾讯云https://mirrors.cloud.tencent.com/nexus/repository/maven-public/华为云https://repo.huaweicloud.com/repository/maven/中央仓库https://repo.maven.apache.org/maven2替换之后执行一次mvn clean install验证通常问题就解决了。3.2 方案二修改或覆盖默认的 HTTP 拦截器如果你的项目确实有特殊原因必须使用HTTP仓库比如公司内网Nexus私服没有配置HTTPS证书那就需要调整默认的拦截器。这里我没有推荐你去删掉$MAVEN_HOME/conf/settings.xml里那段配置因为每次升级Maven版本都可能被覆盖更可控的方式是在用户级~/.m2/settings.xml里覆盖它。方法是在用户级settings.xml中定义一个同样id的镜像来覆盖默认配置mirror idmaven-default-http-blocker/id mirrorOfdummy/mirrorOf urlhttp://0.0.0.0//url /mirror这里把mirrorOf改成一个不存在的仓库IDdummy这样原本的拦截逻辑就失效了Maven会认为这个拦截器只针对一个不存在的仓库自然不会拦其他HTTP请求。这个方法比直接改全局配置温和一些至少全局的默认文件还能保持原样。当然如果你能直接操作$MAVEN_HOME/conf/settings.xml把整个maven-default-http-blocker的mirror节点注释掉或者删掉也是可以的。但要提醒一句关闭拦截器意味着所有HTTP仓库都不设防存在安全风险建议只在可信内网环境使用并且尽量推动私服升级HTTPS。3.3 方案三收敛 mirrorOf别一刀切全镜像很多人配置阿里云镜像时习惯写成mirrorOf*/mirrorOf意思是所有仓库都走这个镜像。这个配置在以前问题不大但现在容易引出两类问题一是当你把镜像URL配成新版HTTPS地址后所有仓库包括中央仓库、JCenter、Spring等全都走阿里云而阿里云某些仓库不一定覆盖所有依赖一旦某个依赖在阿里云上找不到Maven可能因为已镜像而直接放弃原始仓库的搜索表现就是明明能在原始仓库下载的依赖突然消失了。二是配合默认的HTTP拦截器如果某个仓库走了镜像后被映射成一个不存在的地址有可能产生奇怪的Blocked错误。所以我的建议是收敛mirrorOf只镜像真正需要的仓库。最简单稳妥的写法是只镜像中央仓库mirrorOfcentral/mirrorOf如果你公司私服也需要镜像可以这样写把私服排除在外或者明确列出仓库IDmirrorOfcentral,jcenter,!internal-repo/mirrorOf!internal-repo这个感叹号语法表示排除该仓库很实用。这样既能享受镜像加速又不会殃及私有依赖仓库。3.4 方案四给特定 HTTP 仓库单独放行如果你的pom.xml里确实声明了一个HTTP仓库比如这样repositories repository idmy-internal-repo/id urlhttp://nexus.company.com/repository/maven-public//url /repository /repositories而这个nexus.company.com就是内网私服只能通过HTTP访问那么你可以针对这个仓库指定放行。做法是在默认拦截器的mirrorOf中加入排除规则。你需要修改全局settings.xml里的默认拦截器将其中的mirrorOf改为mirrorOfexternal:http:*,!my-internal-repo/mirrorOf这样Maven在检查仓库时就会跳过id为my-internal-repo的仓库其它外部HTTP仓库仍然被拦截安全性影响面也最小。不过这里要提醒一下repository的id不要随便起名字它与拦截器里的排除规则必须是严格匹配的。如果pom.xml里漏写id或者ID里带空格排除规则都不会生效。3.5 方案五临时回退到 Maven 3.6.3不推荐最后一个思路也是最简单粗暴的方法把Maven回退到3.8.1之前的版本。Maven 3.6.3在下载依赖、编译打包上表现也很稳定很多老项目至今还在用它。如果你暂时没有精力调整配置临时换回Maven 3.6.3确实能绕开这个默认拦截器。但我不推荐把回退版本当成长期方案。老版本Maven在性能、依赖冲突解决、插件兼容性上都不如新版而且IDEA新版本对Maven版本的适配也在逐步提高长期停留在老版本会影响开发体验。解决问题的关键还是前面几条把仓库地址切到HTTPS才是顺应方向的做法。4. 实操复现与可直接抄作业的配置4.1 花三分钟完整复现一次这个报错为了让排查思路更清晰建议大家在自己的机器上完整复现一遍这个过程尤其方便验证后续的解决方案是否真实有效。步骤很简单。先确认你本机Maven版本是3.8.1以上然后创建一个最简Maven项目的pom.xml里面明确把中央仓库写成HTTP地址project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdcom.example/groupId artifactIdblocked-mirror-demo/artifactId version1.0-SNAPSHOT/version repositories repository idcentral/id urlhttp://repo.maven.apache.org/maven2/url /repository /repositories /project然后在这个目录下执行mvn clean install你很快就会看到完整的Blocked mirror for repositories报错信息。接下来把url改成https://repo.maven.apache.org/maven2再执行一次问题消失。这个小小的对照实验就能验证我们对原理的理解是对的拦截针对的是HTTP协议而不是某个具体仓库本身。4.2 一份经过生产验证的 settings.xml下面这份配置我用了很久在多个项目里验证过能避免大多数依赖解析问题你可以直接抄作业?xml version1.0 encodingUTF-8? settings xmlnshttp://maven.apache.org/SETTINGS/1.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd localRepository${user.home}/.m2/repository/localRepository mirrors mirror idaliyun-public/id nameAliyun Public/name urlhttps://maven.aliyun.com/repository/public/url mirrorOfcentral/mirrorOf /mirror mirror idaliyun-spring/id nameAliyun Spring/name urlhttps://maven.aliyun.com/repository/spring/url mirrorOfspring-libs-milestone,spring-libs-snapshot/mirrorOf /mirror /mirrors /settings这份配置有两点值得说明第一localRepository明确设置了本地仓库路径避免IDEA和命令行读取的本地仓库不一致第二mirrorOf不是*而是精准指向central和Spring相关的仓库ID。这样既享受了阿里云加速又不会把所有依赖请求都强制转发到云端仓库还能避免一些内网私有依赖被误镜像。4.3 IDEA 里的联动设置别漏掉很多人在命令行能正常构建但IDEA里还是报错原因往往在于IDEA没有使用你配置的settings.xml。你需要打开Settings进入Build, Execution, Deployment选择Build Tools再选Maven然后检查User settings file是否指向了~/.m2/settings.xml。IDEA默认就能找到但如果你改了路径一定要手动指过来。Maven home path选择的是哪个版本。如果在IDEA里看到Bundled (Maven 3.x.x)说明用的是IDEA自带的Maven。建议改成你命令行里用的同一个Maven版本保持行为一致。Local repository是否与settings.xml里的localRepository一致。修改完配置后光点一下右下角的Apply还不够要记得在Maven工具窗口点击Reload All Maven Projects图标或者直接从右侧Maven面板刷新一遍。这一步经常被忽略改完配置不重载IDEA里看到的还是旧状态很容易造成我明明改了对啊怎么还报错的错觉。5. 常见问题排查与避坑指南5.1 常见问题速查表我把这段时间日常碰到的问题整理成了一个速查表方便你有问题的时候直接对照定位问题现象常见原因解决方案IDEA导入Maven项目报Blocked mirrorpom.xml或settings.xml中存在HTTP仓库地址统一改为HTTPS地址或放行指定仓库命令行mvn clean install报Blocked mirrorMaven 3.8.1默认拦截外部HTTP仓库镜像地址升级为HTTPS阿里云镜像下载失败、报403或拦截使用了旧域名nexus/content/groups且为HTTP换成repository/public新版HTTPS地址公司内网私服是HTTP无法访问被external:http:*规则命中在默认拦截器的mirrorOf中用!id排除该仓库settings.xml改了但是不生效IDEA指向了错误的User settings file或未重载项目检查IDEA Maven配置路径并进行Reload All Maven Projects本地仓库混入大量.lastUpdated文件依赖下载失败后缓存了错误状态删除对应目录下的.lastUpdated文件后执行mvn -U5.2 我踩过的四个坑这里分享几个我在排查时走过弯路的地方。第一个坑是只改IDEA里的镜像地址没改命令行的settings.xml。我在IDEA里把阿里云地址换成了新的HTTPS地址后项目成功导入但一跑CI脚本或者直接在终端执行mvn还是报Blocked mirror。原因是命令行和IDE读取的是不同位置的配置。后来我统一把配置放在~/.m2/settings.xml里两边都指向同一个文件才彻底解决。第二个坑是改了镜像地址但没注意某个Spring插件的仓库URL。项目pom.xml里继承了一个父POM父POM中定义了http://repo.spring.io/milestone这个仓库。即使我把镜像地址改成HTTPS那个父POM声明的HTTP仓库依旧会被拦截。最后我是在项目的pom.xml里显式覆盖了父POM的仓库配置才把它绕过去。第三个坑跟mirrorOf有关。我之前写的是mirrorOf*/mirrorOf导致公司私服的仓库请求也被镜像到了阿里云私服里的私有依赖永远拉不下来日志里还看到奇怪的404。把mirrorOf改回central并排除掉私服仓库ID之后一切恢复正常。这个教训就是*虽然省事但会把很多事情搞复杂。第四个坑比较隐蔽我修改了$MAVEN_HOME/conf/settings.xml里的默认拦截器注释掉了maven-default-http-blocker。过了一段时间我升级了Maven版本配置文件被新版本覆盖那个拦截器又回来了私服再次被拦。后来我改用用户级~/.m2/settings.xml来覆盖配置才避免了每次升级都要重新改一遍的问题。5.3 一个很实用的排查命令最后推荐一个排查Maven配置问题的利器——mvn help:effective-settings。它会把Maven实际使用的完整配置输出到终端包括全局配置和用户配置合并后的最终结果。如果你想看最终生效的镜像列表可以这样mvn help:effective-settings -Doutputeffective-settings.xml执行后会把最终配置写入当前目录下的effective-settings.xml文件。打开它直接看mirrors节点就能一眼确认当前有没有默认拦截器、镜像地址是不是HTTPS、mirrorOf匹配规则到底是什么。排查Blocked mirror这类问题我每次都先跑这个命令比在多个配置文件里来回翻要快得多。根据我个人这段时间的体会Blocked mirror这个报错一旦理解了背后的机制解决起来其实很快核心就是围绕HTTP不安全、Maven默认不给放行这一条主线。建议大家升级Maven版本时先检查一遍所有仓库和镜像的URL是不是HTTPS把工程的地址簿打理好远比等报错再排查来得省心。最后分享一个小习惯每次更换Maven版本或者重置settings.xml之后我会先用一个只有依赖web模块的空项目跑一遍mvn clean install验证环境没问题再打开正式项目这样能避开很多莫名其妙的环境问题——配置这东西一次理清楚了能管好几年的清净。
返回列表