简体   繁体   中英

404 for js files when using spring boot with vaadin

I have a problem when using spring security in a vaadin project with spring-boot. So I'am using a PdfViewer Addon to display PDF Files. But I'm getting the following error message:

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

and my spring security configuration looks like this:

@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/**");
    }

So checking the loaded files in Chrome I see a folder /vaadinServlet/APP/PUBLISHED/ and there are all the files needed.

Using the Addon without Spring Security works fine, so anyone any idea?


Update

It doesn't seem to be related to spring security, because I get a similar behavior while testing the Addon in a new simple project. It seems to be a problem with spring boot.

To reproduce this issue you need ( full project for download ):

  • basic spring boot + vaadin app skeleton
  • simple PDF and under /webapp/files
  • PdfViewer add-on in your pom and widgetset compiled
  • the below simple UI
@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);
    }
}
  • open chrome & developer tools with the Network tab selected, access the app and you should see one request for pdf.worker.js fail.

TL;DR; version:

A second request is being triggered by pdf.js to download pdf.worker.js , but it does not match the path /vaadinServlet/APP/PUBLISHED/pdf.worker.js handled by the auto-configured VaadinServlet , it's just /APP/PUBLISHED/pdf.worker.js .

The simplest solution I could come up with, is a controller which forwards the request to the VaadinServlet :

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;
    }
}

Detailed version:

So, I've spent some time debugging this, and it turns out to be a combination of unfortunate configs:

  • spring dispatcher servlet listening
  • vaadin spring servlet listening
  • a pdf.js bugfix/woraround

What happens is, spring registers a DispatcherServlet serving requests for /* . and Vaadin registers a VaadinSpringServlet for the /vaadinServlet/* & /VAADIN paths:

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

To co-exist with the dispatcher servlet and be able to serve requests also on "/*", Vaadin also registers a forwarding-controller for the UI paths. For example requests on /MyUI will be forwarded to /vaadinServlet/MyUI (see the VaadinServletConfiguration sources for more details).

Until now everything works fine and you should not have any issues. Just like you said, looking at the chrome dev-tools all the js files are there, so what's wrong? If you look closley at the requests made when you access your app, you'll notice that actually there are 2 requests for pdf.worker.js - the first one that is successful, and the one which gives you the 404:

pdf.worker.js请求

The Initiator column for the the call that fails, is actually pdf.js:2344 and if you set a breakpoint you can actually see that workerSrc=/APP/PUBLISHED/pdf.worker.js , value which is defined in pl.pdfviewer.client.ui.PdfViewer.java . You may have to scroll horizontally a bit to be able to see the code, so I've formatted it below:

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);
        });
    }

}-*/;

js调试

In a regular Vaadin environment, /APP/PUBLISHED/pdf.worker.js would work out of the box, but we're now in a slightly altered one so we need some adjustments. Bottom line, we can use a similar approach to what Vaadin auto-configuration is doing, and redirect the /APP/PUBLISHED/pdf.worker.js request to /vaadinServlet/APP/PUBLISHED/pdf.worker.js and finally overcome the issue. For the sake of brevity, the redirect controller can be seen at the beginning of this post.

工作pdf

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM