Can I use Vaadin, if my site does not run on a Java server? Let’s say you have a site, a blog or similar on a server that you have no access to, or it even has no Java capabilities, but you would still like to embed and run a Vaadin application there.
To do this you would need to run your Vaadin application on a separate Java server cluster or some popular PaaS cloud service and just embed a Vaadin application into a DIV element on the HTML page on different domain.
Note that, running Vaadin from another domain is different from scenario, where you optimize your Vaadin setup, and put your static files like the widget sets, JavaScript files, images and CSS files to a different server for performance reasons. While it is easy with static files, and iframe or a server-side request proxy is ok for some applications, if you just simply want to embed a whole Vaadin application into your HTML from another domain there is a showstopper:
The same-origin policy web application security model states that HTTP requests with XMLHttpRequest have been forbidden for different domains (It is actually even more strict applying to a combination of scheme, hostname, and port number).
However, there is a viable solution to put Vaadin applications on virtually any web page - regardless of domain restrictions.
Solution: Going CORS
Cross-Origin Resource Sharing (CORS) is a W3C specification that allows cross-domain communication from the browser. This is useful with Vaadin when you want to host the application on a different server than it is actually running on. And this is supported by all the modern browsers.
Now, that sounds promising. But, how do I get started with the CORS setup for my Vaadin app?
First of all, it is useful to understand how the Vaadin client-server communication flow goes. This is visualized in the following pictures for the normal setup and CORS multi-domain setup.
You can see that there are two types of requests from the browser to the server that we need to consider when remotely embedding a Vaadin application: The initial page request (1.) that defines the origin domain, and event requests (3.) for the Vaadin application. The resource requests (2.) are not a problem here, as they have no XMLHttpRequest logic.
For a multi-domain setup with CORS, we need to modify the HTTP headers for requests of type 3. For this, it is enough to override the Servlet class service method for these types of requests. After all, that is where all the magic happens.
Server-side additions
Here is a very simple solution for a servlet implementation. You can do this in the same servlet class you would normally use in your Vaadin app.
As you can see the CORS approach actually uses two request types: The so called preflight OPTION-request, and the actual payload POST-requests. Effectively, this approach bypasses the same-origin security restriction, by adding CORS headers for your Vaadin application UIDL requests, and allows the Vaadin app to communicate to a different domain than where it is actually displayed.
Of course you don’t typically want everyone to be able to embed your application on their site like this. When disabling the cross-site security model, it might allow evil apps to catch the session and exploit XSRF. So you should limit the access only to trusted origin domains.
Embedding the Vaadin application on an HTML page
Let’s get to the client-side modifications and see what you need to do there to enable remote applications.
Basically, this is the same as described in the Book of Vaadin, except that now you can use different domains in your HTML, bootstrap, service and widget set. Just remember to use full URLs instead of relative URIs.
As you can see , you need to modify the XMLHttpRequest in order for the CORS requests to go through with session id: XMLHttpRequest.withCredentials must be set to true. We can use a simple page-wide JavaScript "inherit and override"solution here, although you should that this modification affects all XMLHttpRequests on the page and might have unwanted side effects, if you have some other applications on the same page.
Now you are ready to go. Install your Vaadin application on a Java EE server like before. Create an embedding code with the right URLs and add that to any site you like.
Design your application for CORS
Now, before you go and bypass all the same-origin security in all of your Vaadin applications - just because you can - please note that there are a couple of real-world design decisions you need to make:
-
file:// protocol or scheme is not very well supported. It works in simple cases, but there are places where this scheme is handled differently by the browsers.
-
Do not mix HTTP and HTTPS as it does not work everywhere. For example Google Chrome does not support it at all.
-
Context path does not change anymore, so relying on VaadinRequest.getContextPath() in your application logic does not make sense anymore. URI fragments can be used instead.
-
However, when navigating with URI fragments, setting and getting them might interfere with the hosting page URI fragments, and also affect the back button navigation.
-
Embedding the same application more than once to the same page works nicely, but embedding applications from different domains and versions does not, because the same bootstrap code is used.
-
JavaScript communication between the hosting page and Vaadin application can be handled through JavaScript API. This allows publishing methods that can be called from the host page.
-
Know that CSS is not completely isolated and your application might render a bit differently. When styling the application div, the best option is to use the id selector instead of v-app classname.
-
Naturally the Page.getCurrent() method returns the page we are running on. Remember that Vaadin applications and integration add-ons might also rely on this method for referrer and origin checks, etc.
One good practice can be to keep your “embeddable application UI” separate from the “standalone UI” - and depending on the case: have a separate servlet for these. This way the navigation and path handling can be more reliably built and CORS headers are added only where they need to be.
Anyway, this is cool! You can have a Vaadin application embedded on any website. :)
A small example
That's all. For the sake of an example, I used the code above to embed two interactive charts from an external Vaadin application charts.app.fi/sami/vaadin-community-survey-june-2014 to a separate page at sami.virtuallypreinstalled.com/remote-charts/. It works nicely and feels pretty fast.
There is a forum post for further discussion. See you there!