如何在Heroku部署并访问Java WebSocket端点(无需额外框架)
嘿,我刚好折腾过类似的场景,不用额外框架部署原生Java WebSocket端点到Heroku完全可行,下面是一步步的实操流程,你可以跟着来:
1. 规整项目结构
首先确保你的项目是标准Java Web项目,核心要有:
- 你的WebSocket端点类(比如Oracle教程里的
EchoEndpoint) - 可选但推荐保留
WEB-INF/web.xml(Servlet 3.0+也可用注解,但兼容性更好) - 用Maven/Gradle做依赖管理(Heroku对这俩支持最友好)
2. 添加Heroku适配的构建配置
如果你用Maven:
在pom.xml里补充插件和Java版本配置:
<properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <build> <plugins> <!-- 打包WAR包用 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> <!-- Heroku部署插件 --> <plugin> <groupId>com.heroku.sdk</groupId> <artifactId>heroku-maven-plugin</artifactId> <version>3.0.0</version> </plugin> </plugins> </build>
如果你用Gradle:
在build.gradle里配置WAR插件和版本:
plugins { id 'war' id 'com.heroku.sdk.heroku-gradle' version '3.0.0' } java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 }
3. 配置嵌入式Tomcat与Procfile(关键步骤)
Heroku没有内置Servlet容器,所以我们用嵌入式Tomcat来运行Web应用,不用额外框架,纯原生依赖:
第一步:添加嵌入式Tomcat依赖
Maven:
<dependencies> <!-- 嵌入式Tomcat核心 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>9.0.75</version> <scope>provided</scope> </dependency> <!-- Tomcat WebSocket支持 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-websocket</artifactId> <version>9.0.75</version> <scope>provided</scope> </dependency> <!-- Servlet API --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies>
Gradle:
dependencies { providedCompile 'org.apache.tomcat.embed:tomcat-embed-core:9.0.75' providedCompile 'org.apache.tomcat.embed:tomcat-embed-websocket:9.0.75' providedCompile 'javax.servlet:javax.servlet-api:4.0.1' }
第二步:写启动类
创建Main.java,用来启动嵌入式Tomcat,必须读取Heroku分配的端口:
import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.websocket.server.WsSci; import java.io.File; public class Main { public static void main(String[] args) throws LifecycleException { // 读取Heroku的PORT环境变量,不能硬编码端口 String port = System.getenv("PORT"); if (port == null || port.isEmpty()) { port = "8080"; } Tomcat tomcat = new Tomcat(); tomcat.setPort(Integer.parseInt(port)); // 绑定Web应用目录(假设你的静态文件在src/main/webapp下) Context context = tomcat.addWebapp("", new File("src/main/webapp").getAbsolutePath()); // 注册WebSocket端点的初始化器 context.addServletContainerInitializer(new WsSci(), null); // 若用注解式端点,添加WebSocket监听器 context.addApplicationListener("org.apache.tomcat.websocket.server.WsContextListener"); tomcat.start(); tomcat.getServer().await(); } }
第三步:创建Procfile
在项目根目录新建Procfile文件,告诉Heroku怎么启动应用:
web: java -cp target/classes:target/dependency/* Main
注:Maven用户要先运行
mvn dependency:copy-dependencies把依赖复制到target/dependency目录;Gradle用户可以调整路径为build/classes/java/main:build/dependency/*
4. 本地测试
先在本地验证是否能正常运行:
- Maven:
mvn clean install dependency:copy-dependencies java -cp target/classes:target/dependency/* Main - Gradle:
gradle build java -cp build/classes/java/main:build/dependency/* Main
然后用WebSocket客户端连接ws://localhost:8080/echo(对应你的端点路径),测试消息收发是否正常。
5. 部署到Heroku
确保你已经安装Heroku CLI并登录:
heroku login
初始化Git仓库(如果还没弄):
git init git add . git commit -m "Initial native Java WebSocket deployment"
创建Heroku应用:
heroku create your-custom-app-name
推送代码部署:
git push heroku main
部署完成后,用heroku open打开应用,WebSocket连接地址要换成wss://your-custom-app-name.herokuapp.com/echo(Heroku用HTTPS,对应WebSocket协议是wss)。
常见坑点
- 端口必须用Heroku的
PORT环境变量,硬编码会直接部署失败 - WebSocket端点的路径要和注解一致,比如
@ServerEndpoint("/echo")就对应wss://xxx.herokuapp.com/echo - 嵌入式Tomcat的WebSocket依赖不能少,否则端点不会被注册
内容的提问来源于stack exchange,提问作者coderodde

