问题描述
在使用 Docker Compose 部署周报系统后,前端访问登录接口时出现 502 Bad Gateway 错误:
POST http://172.16.xxx.xxx:5173/api/login 502 (Bad Gateway)前端控制台错误信息:
AxiosError:Request failedwithstatus code502atot(request-BdhJx_rg.js:3:1078)at XMLHttpRequest.E(request-BdhJx_rg.js:3:5798)问题分析
1. 502 Bad Gateway 错误含义
502 Bad Gateway 表示 Nginx 作为反向代理无法连接到后端服务。常见原因包括:
- 后端容器未启动或已崩溃
- 后端服务监听端口配置错误
- 后端服务启动失败
- 网络连接问题
2. 排查步骤
第一步:检查容器状态
docker-composeps所有容器是否都在运行,不应该啊!!!??
第二步:查看后端日志
docker-composelogs backend --tail=100关键发现:
weekly-backend | no main manifest attribute, in app.jar weekly-backend | no main manifest attribute, in app.jar weekly-backend | no main manifest attribute, in app.jar ...这个错误信息表明:jar 包中缺少主清单属性,导致 Java 无法找到主类来启动应用程序。
为什么?我明明存在该jar包,为什么会出现缺少主清单的app.jar
进一步分析
1. 检查 jar 包清单文件
unzip-p weekly.jar META-INF/MANIFEST.MF发现的问题:
Manifest-Version: 1.0 Created-By: Maven JAR Plugin 3.4.1 Build-Jdk-Spec: 11啊?为什么清单文件内容不完整,缺少了 Spring Boot 可执行 jar 包所需的关键属性。
2. 正确的清单文件应该包含
Manifest-Version: 1.0 Created-By: Maven JAR Plugin 3.4.1 Build-Jdk-Spec: 11 Main-Class: org.springframework.boot.loader.JarLauncher ← 缺少 Start-Class: com.example.SpringbootApplication ← 缺少 Spring-Boot-Version: 2.6.13 ← 缺少 Spring-Boot-Classes: BOOT-INF/classes/ ← 缺少 Spring-Boot-Lib: BOOT-INF/lib/ ← 缺少3. 根本原因
检查pom.xml文件发现配置错误:
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.Car-endApplication</mainClass>← 主类名称错误<skip>true</skip>← 跳过构建</configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin>问题分析:
- 主类名称错误:
com.example.Car-endApplication应该是com.example.SpringbootApplication - 跳过构建:
<skip>true</skip>导致打包时跳过了 Spring Boot Maven Plugin 的 repackage 阶段 - 结果:生成的是普通 jar 包而不是可执行的 Spring Boot fat jar
如果
pom.xml文件没有发现配置错误?那就是IDEA受网络波动影响导致打包一半(作者就是出现这个原因,真的是百思不得其解!气死了)
解决方案
1. 修复 pom.xml 配置
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>com.example.SpringbootApplication</mainClass></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin>修改内容:
- 修正主类名称:
com.example.Car-endApplication→com.example.SpringbootApplication - 删除跳过构建配置:移除
<skip>true</skip>
2. 重新打包项目
在本地开发机器上执行:
cdd:\jiangcaidu\code\周报\Weekly_end# 清理并重新打包mvn clean package -DskipTests3. 验证打包结果
# 查看 jar 包大小dirtarget\Weekly_end-0.0.1-SNAPSHOT.jar# 查看清单文件jar xf target\Weekly_end-0.0.1-SNAPSHOT.jar META-INF\MANIFEST.MFtypeMETA-INF\MANIFEST.MF正确的清单文件:
Manifest-Version: 1.0 Created-By: Maven JAR Plugin 3.4.1 Build-Jdk-Spec: 11 Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.example.SpringbootApplication Spring-Boot-Version: 2.6.13 Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx Spring-Boot-Layers-Index: BOOT-INF/layers.idx终于是正确了!
jar 包特征:
- 文件大小:50MB - 100MB(包含所有依赖)
- 清单文件包含
Main-Class和Start-Class
4. 接着上传新的 jar 包到服务器
# 在服务器上,备份旧的 jar 包mvweekly.jar weekly.jar.backup# 上传新的 jar 包到这个目录,并重命名为 weekly.jar5. 重新构建 Docker 镜像
关键步骤:必须重新构建 Docker 镜像,因为 Dockerfile 中的COPY weekly.jar app.jar会在构建时将 jar 包复制到镜像内部。
# 停止并删除旧容器docker-composedown# 重新构建后端镜像(使用新的 jar 包)docker-composebuild backend# 启动服务docker-composeup -d# 查看后端日志docker-composelogs backend -f6. 验证服务启动成功
后端启动成功后,日志应该显示:
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.13) ... Started SpringbootApplication in X.XXX seconds (JVM running for X.XXX)参考资源
- Spring Boot Maven Plugin 文档
- Dockerfile 最佳实践
- Docker Compose 文档
- Maven 打包指南
如果部署中遇到502 Bad Gateway,觉得有帮助,欢迎点赞收藏!有问题欢迎评论区交流~