Playframework [Scala]生产环境无法访问资产文件求助排查
咱们先看你贴出来的错误栈,核心问题其实是Java 9+的模块系统(JPMS)拦住了Play框架的内部类访问sun的私有API——sun.net.www.protocol.file.FileURLConnection是Java基础模块java.base里的内部类,Java 9及以后默认不会把这类内部类暴露给未命名模块(你的Play应用正好运行在未命名模块里),所以直接触发了IllegalAccessError。
至于开发环境正常、生产环境出问题,大概率是开发时用的Java版本低于9,或者开发模式下Play自动帮你加了必要的JVM参数,而生产环境没配置这部分。
下面是具体的调试和解决步骤,你可以一步步来:
1. 先确认开发/生产环境的Java版本差异
分别在开发和生产环境执行这条命令,看版本是否一致:
java -version
如果生产环境用的是Java 9+,开发环境是Java 8,那这就是问题根源——Java 8没有模块系统,不会限制内部API的访问。
2. 添加JVM启动参数解决模块访问限制
如果生产环境必须用Java 9+,那得给Play应用的JVM加个参数,让java.base模块把sun.net.www.protocol.file包开放给未命名模块:
- 要是用
sbt runProd启动,修改命令成这样:sbt -J--add-exports=java.base/sun.net.www.protocol.file=ALL-UNNAMED runProd - 如果是打包成jar后启动,命令改成:
java --add-exports java.base/sun.net.www.protocol.file=ALL-UNNAMED -jar your-app.jar
3. 检查Play框架版本兼容性
这个问题一般出在比较旧的Play版本(比如2.6.x及更早),这些版本没适配Java 9+的模块系统。如果条件允许,升级到Play 2.7+或者更高版本,官方在新版本里已经修复了这类JPMS兼容性问题,不用手动加JVM参数就能解决。
4. 快速验证资产配置的正确性
虽然核心问题在JVM层面,但也可以快速确认资产配置没问题:
- 确认
public/assets/images/favicon.png文件确实存在于生产环境的应用目录,或者打包后的jar包里面 - 检查路由配置
GET /assets/*file controllers.Assets.versioned(file)是否正确——Play 2.6+用versioned方法,旧版本可能是Assets.at,别搞混了 - 看一下页面源码,确认
assetsFinder.path("images/favicon.png")是不是正确生成了/assets/images/favicon.png的URL
5. 排查Nginx代理的影响
你说Nginx能代理应用,但还是可以检查下Nginx有没有正确转发资产请求:
- 看Nginx的access日志,确认
/assets/images/favicon.png的请求确实转发到了Play应用的9000端口 - 直接访问Play应用的
IP:9000/assets/images/favicon.png,跳过Nginx,看看是不是还是报错,排除Nginx配置的干扰
按上面的步骤一步步来,优先解决Java版本和JVM参数的问题,这是触发错误的核心原因。
内容的提问来源于stack exchange,提问作者o-0

