Heroku部署JavaWeb WAR包报UnsupportedClassVersionError及404错误
问题修复方案
两个错误为独立原因导致,按优先级逐个修复即可:
1. 修复 java.lang.UnsupportedClassVersionError 错误
错误根因:本地编译WAR包使用的JDK版本高于Heroku运行环境的JRE版本,高版本编译生成的class文件无法在低版本JVM上加载运行。
修复方式二选一即可:
- 对齐Heroku运行环境版本:在项目根目录新建
system.properties配置文件,写入和本地一致的JDK版本,例如本地使用JDK11则写入java.runtime.version=11,使用JDK17则写入java.runtime.version=17,将该文件随WAR包一同提交部署,Heroku会自动安装匹配版本的JDK。 - 降低本地编译版本:打开Eclipse,右键项目→Properties→Java Compiler,将Compiler compliance level调整为1.8(Heroku默认JDK版本为8),重新打包WAR部署。
2. 修复重复提交返回404错误
该错误由三类问题叠加触发,按以下步骤修复:
2.1 修正Servlet代码缺陷
现有代码存在三处会直接导致请求失败的问题:
- SQL执行语句写法错误:
creado = ps.execute;为非法语法,execute是方法不是属性,需改为ps.executeUpdate()判断插入结果 - 资源关闭逻辑未做空判断:如果数据库连接初始化失败,
ps/con为null时直接调用close()会抛出空指针,直接中断请求 - 请求转发使用相对路径:未从应用根路径匹配JSP资源,路径拼接异常时会找不到文件
修正后的完整Servlet核心代码如下:
@WebServlet("/Servlet") public class Servlet extends HttpServlet { private static final long serialVersionUID = 1L; public Servlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean crear = create(request.getParameter("correo"),request.getParameter("nombre_usuario"),request.getParameter("pass")); if(crear){ // 路径前加/,从应用根目录匹配资源,避免相对路径拼接错误 request.getRequestDispatcher("/correcto.jsp").forward(request, response); }else { request.getRequestDispatcher("/index.jsp").forward(request, response); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } public boolean create(String correo, String nombre_usu, String password) { boolean creado = false; Connection con = null; PreparedStatement ps = null; try{ Class.forName("com.mysql.cj.jdbc.Driver"); con = DriverManager.getConnection("jdbc:mysql://XXXXXX","XXXXXXX","XXXXXXXXX"); String sql = "INSERT INTO usuarios (correo,nombre_usuario,clave) VALUES (?,?,?)"; ps = con.prepareStatement(sql); ps.setString(1, correo); ps.setString(2, nombre_usu); ps.setString(3, password); // 修正SQL执行逻辑,受影响行数大于0即判定插入成功 creado = ps.executeUpdate() > 0; } catch (SQLException | ClassNotFoundException e) { e.printStackTrace(); }finally { // 增加非空判断,避免空指针异常 try { if(ps != null) ps.close(); if(con != null) con.close(); } catch (SQLException e) { e.printStackTrace(); } } return creado; } }
2.2 修正表单提交路径
不要在JSP中硬编码相对路径,通过EL表达式动态获取应用上下文路径,避免部署路径变化时提交地址失效。
将index.jsp中的form标签修改为:
<form action="${pageContext.request.contextPath}/Servlet" method="GET">
2.3 校验包结构与启动配置
- 确认
index.jsp、correcto.jsp放在WAR包根目录(与WEB-INF文件夹同级),不要放在WEB-INF目录内,否则无法被请求转发找到 - 确认Heroku部署时使用的Tomcat/Webapp Runner版本支持Servlet 3.0+注解(Tomcat7及以上版本支持@WebServlet注解,建议使用Tomcat9及以上稳定版本)
- 首次报类版本错误时应用实际未启动成功,必须先解决JDK版本匹配问题,保证应用正常启动后再测试业务逻辑,否则所有请求都会返回404
额外排查建议
- 部署后通过Heroku日志命令查看实时启动日志,优先解决启动阶段抛出的异常,再验证业务逻辑
- 确认你的MySQL服务对公网开放访问,Heroku平台无法访问内网/本地数据库,若使用云数据库需将Heroku出口IP加入数据库白名单,建议直接使用Heroku平台提供的MySQL插件降低配置成本
内容的提问来源于stack exchange,提问作者frann
相关产品推荐
相关产品推荐

