【问题标题】:404 for js files when using spring boot with vaadin使用带有 vaadin 的 spring boot 时 js 文件的 404
【发布时间】:2017-12-30 12:42:01
【问题描述】:

在带有 spring-boot 的 vaadin 项目中使用 spring security 时遇到问题。所以我正在使用 PdfViewer 插件来显示 PDF 文件。但我收到以下错误消息:

error:"Not Found"
message:"No message available"
path:"/APP/PUBLISHED/pdf.worker.js"
status:404

我的 spring 安全配置如下所示:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .headers()
                .defaultsDisabled()
                .frameOptions().sameOrigin().and()
                .csrf().disable() // Use Vaadin's CSRF protection
                .authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/vaadinServlet/HEARTBEAT/**").permitAll()
                .antMatchers("/vaadinServlet/UIDL/**").permitAll()
                .antMatchers("/vaadinServlet/APP/PUBLISHED/**").permitAll()
                .antMatchers("login?debug").permitAll()
                .antMatchers("/#!pwdreset/*").permitAll()
                .antMatchers("/pwdreset/*").permitAll()
                .and()
                .authorizeRequests()
                .and()
                .formLogin().loginPage("/#!login").permitAll()
                .and()
                .logout().logoutUrl("/#!login?logout").logoutSuccessUrl("/").permitAll().and()
                .sessionManagement().sessionFixation().newSession();

    }

@Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**", "/VAADIN/**");
    }

所以在 Chrome 中检查加载的文件时,我看到了一个文件夹 /vaadinServlet/APP/PUBLISHED/,里面有所有需要的文件。

在没有 Spring Security 的情况下使用插件可以正常工作,所以有人知道吗?


更新

它似乎与弹簧安全性无关,因为我在一个新的简单项目中测试插件时遇到了类似的行为。好像是spring boot的问题。

要重现此问题,您需要 (full project for download):

  • 基本 Spring Boot + vaadin 应用程序框架
  • 简单的PDF及以下/webapp/files
  • PdfViewer add-on 在你的 pom 和 widgetset 中编译
  • 下面的简单用户界面
@Theme("mytheme")
@SpringUI
@Widgetset("org.test.AppWidgetSet")
public class MyUI extends UI {
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        final VerticalLayout layout = new VerticalLayout();
        String basepath = VaadinService.getCurrent().getBaseDirectory().getAbsolutePath();
        File file = new File(basepath.concat("/files/test.pdf"));
        if (file.exists()) {
            PdfViewer pdfViewer = new PdfViewer(file);
            Label info = new Label("File was found!");
            layout.addComponents(info, pdfViewer);
        } else {
            Label info = new Label("no file found!");
            layout.addComponent(info);
        }
        setContent(layout);
    }
}
  • 在选中Network 选项卡的情况下打开 chrome 和开发人员工具,访问该应用,您应该会看到一个对 pdf.worker.js 的请求失败。

【问题讨论】:

  • 您能否提供sscce 来重现您的问题?没什么特别的,只是产生此错误的最小 pom、UI、spring-boot 配置和启动器(主类)。我看不出您的配置有什么问题,也许您可​​以将所有静态资源路径移动到 configure 方法中的 ignore 匹配器列表,但无论如何这应该不是问题。我有一个类似的设置,但我的工作正常,所以如果不复制它就很难理解(至少对我来说)
  • @Morfic 我刚刚更新了我的问题,因为这似乎是 Spring Boot 的问题,与 Spring Security 无关。在创建示例时,我遇到了与我的项目中相同的错误。可能您对如何解决此问题有任何想法。

标签: java spring spring-boot spring-security vaadin


【解决方案1】:

TL;DR; 版本:

pdf.js 触发了第二个下载pdf.worker.js 的请求,但它与自动配置的VaadinServlet 处理的路径/vaadinServlet/APP/PUBLISHED/pdf.worker.js 不匹配,它只是/APP/PUBLISHED/pdf.worker.js

我能想出的最简单的解决方案是一个控制器,它通过forwardsVaadinServlet 发出请求:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class PdfJsRedirectController {
    private static final String WORKER_JS_INCORRECT_PATH = "/APP/PUBLISHED/pdf.worker.js";
    private static final String WORKER_JS_CORRECT_FORWARD_PATH = "forward:/vaadinServlet/APP/PUBLISHED/pdf.worker.js";

    @RequestMapping(value = WORKER_JS_INCORRECT_PATH)
    public String forwardWorkerJsRequestToVaadin() {
        return WORKER_JS_CORRECT_FORWARD_PATH;
    }
}

详细版本:

所以,我花了一些时间对此进行调试,结果证明这是一个不幸的配置的组合:

  • spring dispatcher servlet 监听
  • vaadin spring servlet 监听
  • pdf.js 错误修复/解决方法

发生的情况是,spring 注册了一个DispatcherServlet/* 服务请求。并且 Vaadin 为 /vaadinServlet/*/VAADIN 路径注册了一个 VaadinSpringServlet

ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
ServletRegistrationBean  : Mapping servlet: 'springVaadinServlet' to [/vaadinServlet/*, /VAADIN/*]

为了与调度程序 servlet 共存并能够在“/*”上处理请求,Vaadin 还为 UI 路径注册了一个转发控制器。例如,/MyUI 上的请求将被转发到/vaadinServlet/MyUI(有关详细信息,请参阅VaadinServletConfiguration sources)。

到目前为止,一切正常,您应该没有任何问题。就像您说的那样,查看 chrome dev-tools 所有的js 文件都在那里,那有什么问题?如果您仔细查看访问应用程序时发出的请求,您会注意到实际上有 2 个针对 pdf.worker.js 的请求 - 第一个是成功的,另一个是 404:

调用失败的Initiator 列实际上是pdf.js:2344,如果您设置断点,您实际上可以看到workerSrc=/APP/PUBLISHED/pdf.worker.js,该值在pl.pdfviewer.client.ui.PdfViewer.java 中定义。您可能需要水平滚动一点才能看到代码,所以我将其格式化如下:

public native void loadResourcePdf(String fileName, VPdfViewer instance)/*-{
    var pdfviewer = instance.@pl.pdfviewer.client.ui.VPdfViewer::jsObject;
    pdfviewer.work = false;
    if ((pdfviewer.fileName == null || pdfviewer.fileName != fileName) && fileName != null) {
        $wnd.PDFJS.disableStream = true;
======> $wnd.PDFJS.workerSrc = 'APP/PUBLISHED/pdf.worker.js';
        $wnd.PDFJS.getDocument(fileName).then(function (pdf) {
            pdfviewer.pdfFile = pdf;
            pdfviewer.fileName = fileName;
            pdfviewer.pageCount = pdf.numPages;
            if (pdfviewer.pageNumber == 0 && pdf.numPages > 0) {
                pdfviewer.pageNumber = 1;
            }
            pdfviewer.showPdfPage(pdfviewer.pageNumber);
        });
    }

}-*/;

在常规的 Vaadin 环境中,/APP/PUBLISHED/pdf.worker.js 可以开箱即用,但我们现在处于稍微改变的环境中,因此我们需要进行一些调整。最重要的是,我们可以使用与 Vaadin 自动配置类似的方法,并将 /APP/PUBLISHED/pdf.worker.js 请求重定向到 /vaadinServlet/APP/PUBLISHED/pdf.worker.js 并最终解决该问题。为简洁起见,重定向控制器可以在本文开头看到。

【讨论】:

  • 谢谢,这行得通!我没有看消息来源。我将为插件创建者创建一个问题。
  • @RedGato 没问题。还没有时间进一步调查,但我不确定他是否可以做点什么。如果可以动态确定路径,那么我们可以进行修复,否则我们仍然需要依赖此解决方法。尽管如此,如果您确实打开了该问题,请确保添加此问题的链接以供参考。干杯
猜你喜欢
  • 1970-01-01
  • 2015-06-14
  • 1970-01-01
  • 1970-01-01
  • 2018-07-28
  • 2020-01-29
  • 2017-05-02
  • 2016-04-08
  • 1970-01-01
相关资源
最近更新 更多