1

I've already posted this question in the Vaadin Forum, unfortunately I did not get any response - maybe answer of the question lies somewhere between spring-boot and Vaadin.

currently I'm having a hard time embedding a Vaadin application into an HTML page.

What do I use:

Vaadin 7.6.6
vaadin-spring
spring-boot 1.3.5.RELEASE

To enable CORS in combination with spring-boot, I adapted Sami's Blog entry and created the following custom CORS servlet:

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;

import com.vaadin.spring.server.SpringVaadinServlet;

/**
 * This custom {@link SpringVaadinServlet} enables CORS in combination with
 * Spring.
 *
 * @author Christoph Guse
 *
 */
public class CORSServlet extends SpringVaadinServlet {

    /**
     *
     */
    private static final long serialVersionUID = -2482991123719720492L;

    /**
     * Override to handle the CORS requests.
     */
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Origin is needed for all CORS requests
        String origin = request.getHeader("Origin");
        if (origin != null && isAllowedRequestOrigin(origin)) {

            // Handle a preflight "option" requests
            if ("options".equalsIgnoreCase(request.getMethod())) {
                response.addHeader("Access-Control-Allow-Origin", origin);
                response.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");

                // allow the requested method
                String method = request.getHeader("Access-Control-Request-Method");
                response.addHeader("Access-Control-Allow-Methods", method);

                // allow the requested headers
                String headers = request.getHeader("Access-Control-Request-Headers");
                response.addHeader("Access-Control-Allow-Headers", headers);

                response.addHeader("Access-Control-Allow-Credentials", "true");
                response.setContentType("text/plain");
                response.setCharacterEncoding("utf-8");
                response.getWriter().flush();
                return;
            } // Handle UIDL post requests
            else if ("post".equalsIgnoreCase(request.getMethod())) {
                response.addHeader("Access-Control-Allow-Origin", origin);
                response.addHeader("Access-Control-Allow-Credentials", "true");
                super.service(request, response);
                return;
            }
        }

        // All the other requests nothing to do with CORS
        super.service(request, response);

    }

    /**
     * Check that the page Origin header is allowed.
     */
    private boolean isAllowedRequestOrigin(String origin) {
        // TODO: Remember to limit the origins.
        return origin.matches(".*");
    }

}

Additionally I found some documentation about spring-boot and CORS, so I added this Spring configuration:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import CORSServlet;

/**
 * @author Christoph Guse
 *
 */
@Configuration
public class AuthAppVaadinApplicationConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer(){
        return new WebMvcConfigurerAdapter() {

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins(".*");
            }

        };
    }

    @Bean(name="vaadinServlet")
    public CORSServlet corsServlet(){

        return new CORSServlet();

    }

}

My HTML looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible"
content="IE=9;chrome=1" />

<title>Embedding a Vaadin Application in HTML Page</title>

<!-- Set up the favicon from the Vaadin theme -->
<link rel="shortcut icon" type="image/vnd.microsoft.icon"
href="/VAADIN/themes/reindeer/favicon.ico" />
<link rel="icon" type="image/vnd.microsoft.icon"
href="/VAADIN/themes/reindeer/favicon.ico" />
</head>

<body>
<!-- Loads the Vaadin widget set, etc. -->
<script type="text/javascript"
src="http://vaadin.poc:8090/VAADIN/vaadinBootstrap.js?v=7.6.6"></script>

<h1>Embedding a Vaadin UI</h1>

<p>This is a static web page that contains an embedded Vaadin
application. It's here:</p>

<!-- So here comes the div element in which the Vaadin -->
<!-- application is embedded. -->
<div style="width: 100%; height: 75vh; border: 2px solid green;"
id="helloworld" class="v-app">

<!-- Optional placeholder for the loading indicator -->
<div class=" v-app-loading"></div>

<!-- Alternative fallback text -->
<noscript>You have to enable javascript in your browser to
use an application built with Vaadin.</noscript>
</div>

<script type="text/javascript">//<![CDATA[
if (!window.vaadin)
alert("Failed to load the bootstrap JavaScript: "+
"VAADIN/vaadinBootstrap.js");

/* The UI Configuration */
vaadin.initApplication("helloworld", {
"browserDetailsUrl": "http://vaadin.poc:8090/",
"serviceUrl": "http://vaadin.poc:8090/",
"theme": "valo",
"versionInfo": {"vaadinVersion": "7.6.6"},
"widgetset": "com.vaadin.DefaultWidgetSet",
"vaadinDir": "http://vaadin.poc:8090/VAADIN/",
"heartbeatInterval": 300,
"debug": true,
"standalone": false,
"authErrMsg": {
"message": "Take note of any unsaved data, "+
"and <u>click here<\/u> to continue.",
"caption": "Authentication problem"
},
"comErrMsg": {
"message": "Take note of any unsaved data, "+
"and <u>click here<\/u> to continue.",
"caption": "Communication problem"
},
"sessExpMsg": {
"message": "Take note of any unsaved data, "+
"and <u>click here<\/u> to continue.",
"caption": "Session Expired"
}
});//]] >
</script>

<p>Please view the page source to see how embedding works.</p>
</body>
</html>

My problem is the application is initally loaded, but several icons are missing and if I trigger an action in the appliction, i.e. open a dropbox, then the application is not able to do the connect to the spring-boot application. Error messages look like this:

XMLHttpRequest cannot load http://vaadin.poc:8090/UIDL/?v-uiId=0. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 403.

Is there anybody out there who managed to embed a Vaadin spring-boot application into another HTML application?

Any hint is highly appreciated! Christoph

flexguse
  • 479
  • 6
  • 22
  • For a better discussion base I created a demo application which can be found on GitHub https://github.com/flexguse/vaadin-html-embedding. Unfortunately I did not make any progress so far. – flexguse Jul 08 '16 at 16:04

1 Answers1

1

fortunately someone in the Vaadin forum gave me the missing link. I forgot to add some JavaScript in the standalone HTML:

    <script>
        XMLHttpRequest.prototype._originalSend = XMLHttpRequest.prototype.send;
        var sendWithCredentials = function(data) {
            this.withCredentials = true;
            this._originalSend(data);
        };
        XMLHttpRequest.prototype.send = sendWithCredentials;
    </script>

That helped, but the fonts were not properly loaded by CORS problems, so I removed the custom Vaadin CORSServlet and added the filter based CORS support provided by spring-boot (as explained in this blog article).

My example now runs properly, the demo application is fully functional, fonts are loaded and used correctly.

Please have a look at https://github.com/flexguse/vaadin-html-embedding to get the fully working example.

Cheers, Christoph

flexguse
  • 479
  • 6
  • 22