undertow模式无法响应静态资源的请求

如果html模板中引入了本地的js文件会报404错误,请问是否undertow默认不响应静态资源的请求?

评论区

JFinal

2019-01-05 16:14

参考首页的 jfinal demo for maven, 必须会支持

myth4ian

2019-01-05 16:22

Starting Undertow Server http://0.0.0.0:80, https://0.0.0.0:443
java.lang.RuntimeException: File not found : C:\Users\xxb-ian\Desktop\jfinal_demo_for_maven/common/_layout.html
at com.jfinal.template.source.FileSource.getContent(FileSource.java:70)
at com.jfinal.template.EngineConfig.doAddSharedFunction(EngineConfig.java:93)
at com.jfinal.template.EngineConfig.addSharedFunction(EngineConfig.java:88)
at com.jfinal.template.Engine.addSharedFunction(Engine.java:245)
at com.demo.common.DemoConfig.configEngine(DemoConfig.java:68)
at com.jfinal.core.Config.configJFinal(Config.java:57)
at com.jfinal.core.JFinal.init(JFinal.java:61)
at com.jfinal.core.JFinalFilter.init(JFinalFilter.java:62)
at io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:111)
at io.undertow.servlet.core.ManagedFilter.createFilter(ManagedFilter.java:80)
at io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:589)
at io.undertow.servlet.core.DeploymentManagerImpl$2.call(DeploymentManagerImpl.java:554)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.core.DeploymentManagerImpl.start(DeploymentManagerImpl.java:596)
at com.jfinal.server.undertow.UndertowServer.configHttp(UndertowServer.java:276)
at com.jfinal.server.undertow.UndertowServer.doStart(UndertowServer.java:254)
at com.jfinal.server.undertow.UndertowServer.start(UndertowServer.java:151)
at com.jfinal.server.undertow.UndertowServer.start(UndertowServer.java:80)
at com.demo.common.DemoConfig.main(DemoConfig.java:33)

myth4ian

2019-01-05 16:23

感觉是路径的问题 undertow感觉不能正确识别src/main/webapp这个路径

JFinal

2019-01-05 16:24

异常信息: C:\Users\xxb-ian\Desktop\jfinal_demo_for_maven/common/_layout.html

路径中没有包含 src/main/webapp , 证明项目导入有问题

估计你是 IDEA 导入项目时,并没有按 maven 项目来导入,而仅仅是打开项目,文档中早有说明:
https://www.jfinal.com/doc/1-5

myth4ian

2019-01-05 16:24

@JFinal 麻烦大佬看一下上面的报错 ,跑的就是首页的maven demo,因为没有数据库,我注释掉了configPlugin里面的数据源配置。

myth4ian

2019-01-05 16:51

@JFinal 我用的是vscode redhat java扩展打开的 可能是IDE的问题了 ,我再试试看看。

JFinal

2019-01-05 16:59

@myth4ian 使用一段测试代码,输出一下项目能读到的当前路径:
System.out.print(new File(".").getAbsolutelyPath());

根据这个路径调整一下 undertow.resourcePath 的配置即可,缺什么路径就加什么路径

myth4ian

2019-01-05 17:14

@JFinal 好的 我试试看。

myth4ian

2019-01-05 17:20

@JFinal System.out.println(JFinal.me().getServletContext().getRealPath("/")); 这个输出了null ,应该是和这个有关系了导致不能正确识别到web根目录。

JFinal

2019-01-05 17:30

@myth4ian 跟 getServletContext().getRealPath("/") 这个没有关系, 因为你的 undertow.resourcePath 配置不对,所以上面那个值必为 null

JFinal

2019-01-05 17:31

而 undertow.resourcePath 默认是可以的,但你用的开发工具没能正确得到项目当前路径,用我前面介绍的办法输出:
System.out.print(new File(".").getAbsolutelyPath());

然后再改 undertow.resourcePath

myth4ian

2019-01-05 21:41

@JFinal
System.out.print(new File(".").getAbsolutelyPath());
这个测试了能输出项目的根目录的绝对路径

vscode启动调试到
ResourceManagerKit.class 中buildResourceManager方法里面的时候
0:"src/main/webapp" (id=81)
1:" webapp" (id=82)
2:" src/main/resources/webapp" (id=83)
3:" WebRoot" (id=84)
4:" WebContent" (id=85)

5个预留的地址在if里面都判断失败了 没有加到ret里面去

for (String path : resourcePathArray) {
path = path.trim();
if (new File(path).isDirectory()) {
ret.add(new FileResourceManager(new File(path)));
}
}
但是eclipse中调试就正常了 这就奇怪了。

JFinal

2019-01-05 22:37

@myth4ian System.out.print(new File(".").getAbsolutelyPath());
这个测试了能输出的值是什么?

myth4ian

2019-01-06 08:53

@JFinal
测试了是能输出项目的根目录的绝对路径。

myth4ian

2019-01-06 09:12

@JFinal
调试找到问题所在了。
ResourceManagerKit的buildResourceManager方法里面
ret.add(new FileResourceManager(new File(path)));
FileResourceManager使用的是默认构造
public FileResourceManager(final File base) {
this(base, 1024, true, false, null);
}
FileResourceManager构造第三个参数是文件路径是否大小写敏感,默认为true,这样就导致了在调用getFileResource的时候进入if (this.caseSensitive)分支后进行文件名大小写比对:
else if (isFileSameCase(file, normalizedFile)) {
log.tracef("Found path resource %s from path resource manager with base %s", path, base);
return new PathResource(file, this, path, eTagFunction.generate(file));
}
只有大小写完全一致才能调用PathResource读取资源
而我这里诡异的情况出现了:
private boolean isFileSameCase(final Path file, String normalizeFile) throws IOException {
String canonicalName = file.toRealPath().toString();
return canonicalName.equals(normalizeFile);
}
canonicalName在vscode中返回的盘符是大写,而normalizeFile盘符是小写(如D:/abc.txt与d:/abc.txt),导致两者不一致而返回false,在eclipse中两者盘符大小写是一样的,这样造成了vscode中无法读取到正确的资源。

其实根本原因是windows系统本身对文件路径大小写不敏感,这个情况在linux下因为大小写敏感就没有问题的,所以大佬能否在构建ResourceManager的时候对操作系统进行一下判断来决定new FileResourceManager()时的大小写敏感的参数,或者说提供一个setter让我们自己去设置也行。

JFinal

2019-01-06 23:08

目前建议你通过配置 undertow.resourcePath 为全路径来解决,例如:
undertow.resourcePath=C:/Users/xxb-ian/Desktop/jfinal_demo_for_maven/src/main/webapp

通过 undertow 源码可知 caseSensitive 参数配置为 false 会有更好的性能,所以下一版本 jfinal undertow 考虑将这个值默认弄成 false

myth4ian

2019-01-07 09:47

@JFinal 好的 ,感谢您的指导。

alonecarr

2019-11-20 16:05

@JFinal idea下面,undertow.resourcePath这玩意必须设置成绝对路径吗,我看现在设置成项目相对路径不行

热门反馈

扫码入社