URL Rewriter Rules for Reverse-Proxying External SPA (14.0-14.1)
Introduction
Goal
Implement a reverse proxy using URL rewriter rules in order to serve an external SPA from the same host as the Bloomreach Experience Manager application.
Background
In most SPA integrations, the SPA server is external to Bloomreach Experience Manager. However, in order to make the SPA preview available for editing in the Experience manager, it must be served from the same host as the Bloomreach Experience Manager application. This problem is solved by implementing reverse proxy functionality using the URL rewriter.
Install and Configure the URL Rewriter
Make sure to install the URL Rewriter plugin in your project, and use the following configuration parameters (see Image 1):
/hippo:configuration/hippo:modules/urlrewriter/hippo:moduleconfig: urlrewriter:ignorecontextpath: false urlrewriter:usequerystring: true urlrewriter:skippedprefixes: - /site/_cmsrest - /site/_cmssessioncontext - /site/_rp - /site/_hn: - /site/ping/
Furthermore, make sure that the urlrewriter:skippedprefixes property does contain the value _cmssessioncontext, but does not contain the value _cmsinternal. In case you have context path enabled, also make sure all the prefixes start with /site since urlrewriter:ignorecontextpath is disabled.
Image 1. UrlRewriter module configuration
Set up Reverse Proxy Rules
You need to set up a set of 3 rules for reverse-proxying the requests to your SPA server.
- The first rule makes sure that the requests to the Page Model API are not proxied.
- The second rule ensures that the request contains the query parameter bloomreach-preview=true for requests that pertain to the preview version.
- The third rule actually proxies the request to the external SPA server.
Below rule set is intended for both client- and server-side rendered SPAs, should work locally and in production, both on Bloomreach Cloud and "on-premises".
Make sure to use the _cmsinternal infix, as opposed to the option described on this page.
Below rules do not cover static resources like JS and CSS bundles. Such bundles should be served from an external server, and accessed by the SPA through absolute URLs. The demo SPA implements a PUBLIC_URL environment variable, which it uses to generate these absolute URLs.
When applying the rules, you must adjust them to your specific situation:
- Replace http://localhost:3000 in the third rule with the location of your external SPA server.
- If your project uses a non-default prefix for exposing the Page Model API (as described here), you should replace resourceapi with your custom value in the first rule.
- If the channel hosting your SPA is mounted at a non-empty path below the hostname (e.g. http://www.example.com/channel-path), make sure to use the second set of rules, and replace channel-path with your channel path.
Rules for Empty Channel Path
If your channel path is empty (see previous bullet item), these are the rules to use:
<rule> <!-- Rule 1: Exclude requests for Page Model API and binaries --> <from>^(?:/[^\/]+)?(?:/_cmsinternal)?/(?:binaries|images|resourceapi)([\?/].*)?$</from> <to last="true">-</to> </rule> <rule> <!-- Rule 2: Ensure bloomreach-preview query parameter for preview requests --> <from> ^((?:/[^\/]+)?/_cmsinternal(?:/[^\?]*)?)(?:\?((?!(.*&)?bloomreach-preview=.*).*))?$ </from> <to type="redirect" last="true">$1?$2&bloomreach-preview=true</to> </rule> <rule> <!-- Rule 3: Proxy requests to route to the SPA server --> <from>^(?:/[^\/]+)?(?:/_cmsinternal)?([\?/].*)?$</from> <to type="proxy" last="true">http://localhost:3000$0</to> </rule>
Rules for Non-Empty Channel Path
If your channel path is non-empty (see previous bullet item), these are the rules to use. Remember to replace channel-path with your specific channel path.
<rule> <!-- Rule 1: Exclude requests for Page Model API --> <from>^(?:/[^\/]+)?(?:/_cmsinternal)?/channel-path/resourceapi([\?/].*)?$</from> <to last="true">-</to> </rule> <rule> <!-- Rule 2: Ensure bloomreach-preview query parameter for preview requests --> <from> ^((?:/[^\/]+)?/_cmsinternal/channel-path(?:/[^\?]*)?)(?:\?((?!(.*&)?bloomreach-preview=.*).*))?$ </from> <to type="redirect" last="true">$1?$2&bloomreach-preview=true</to> </rule> <rule> <!-- Rule 3: Proxy requests to route to the SSR SPA --> <from>^(?:/[^\/]+)?(?:/_cmsinternal)?(?:/channel-path)([\?/].*)?$</from> <to type="proxy" last="true">http://localhost:3000$0</to> </rule>