404 for js files when using spring boot with vaadin

我的梦境 提交于 2019-12-01 06:57:39

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:

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

}-*/;

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!