It is becoming more common to connect directly with a Solr cluster from rich client side applications. Performing a search directly against the cluster will require either JSONP or Cross-origin Resource Sharing (CORS). Here we discuss a few methods for connecting with a search resource with CORS.
Let’s assume we have an Angular app running on
app.o19s.com and a Solr cluster available at
search.o19s.com. We attempt to use Angular’s
$http service to perform a query against the
http://search.o19s.com/solr/core/select endpoint. No results are displaying in the application. When we test the Solr URL in another tab the results are displayed. The web inspector displays an XMLHttpRequest error
What’s going on?
In this case our browser performed some checks prior to the request being sent and decided it needed to verify our application has permission to access the
search.o19s.com resource. It then sends a separate “preflight” request first asking if we have access. At this point our Solr cluster doesn’t know how to handle the request and doesn’t respond appropriately. This signals the browser that we do not have permission and the original request is never sent.
How does CORS work?
XMLHttpRequest is performed our browser checks the protocol, domain, and port of the request verifying they match that of our current page. In our example the protocol and port match, but not the domain. This triggers the cross-origin preflight check.
The preflight request is sent by the browser to the resource being accessed. This request is sent with the
OPTIONS HTTP method and an
Origin header. The
Origin header provides the origin that is attempting to access the resource, in our case the header will read
At this point the server should respond with a pair of headers,
Access-Control-Allow-Origin header indicates which origins are permitted access. The browser will take this list and match the origin domain, protocol, and port to see if it is permitted access. The second header,
Access-Control-Allow-Methods, lists all supported HTTP methods. Now the browser checks the
XMLHttpRequest’s method verifying that it matches the
Enabling CORS at the reverse proxy
When running Solr publicly it is recommended to place Solr behind a reverse proxy. We have talked about this previously with IIS, but other web servers like Apache and nginx also offer similar functionality. If your configuration includes a reverse proxy CORS support may be enabled on this level. Enable CORS has a list of configuration entries for many common web servers.
Note this list is not complete, check out Enable CORS if your server is not in this list or continue reading for another approach.
Enabling CORS within the Solr application server
In some environments enabling CORS at the reverse proxy level is not possible. This can be for a variety of reasons, in this case we can move the CORS configuration to the app server level. Solr ships with the Jetty servlet engine. Jetty hosts the Solr WAR and handles requests to the application. We will configure Jetty to serve the appropriate CORS headers when requested, this requires no change to the reverse proxy.
server/webapps/solr.warfile is extracted to
server/solr-webapp/webapp. If not this may be accomplished with the following commands
# Server is the directory where Solr resides
unzip webapps/solr.war -d solr-webapp/webapp
- Download the appropriate libraries (links below direct to search.maven.org’s mirrors)
- Copy the downloaded JAR files to the
server/solr-webapp/webapp/WEB-INF/web.xmlfile to include the following filter right after the
line. On a clean Solr 5.0.0 download this entry will start at line 24.
<filter> <filter-name>cross-origin</filter-name> <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class> <init-param> <param-name>allowedOrigins</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>allowedMethods</param-name> <param-value>GET,POST,OPTIONS,DELETE,PUT,HEAD</param-value> </init-param> <init-param> <param-name>allowedHeaders</param-name> <param-value>origin, content-type, accept</param-value> </init-param> </filter> <filter-mapping> <filter-name>cross-origin</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Note that the
allowedOriginsvalue here is
*which permits access from all origins. Consider setting this value to the domain where your application is hosted (ex:
allowedMethodsparam may also be trimmed to just the methods needed by your application (ex:
- Restart Solr
Test the CORS changes have been applied with cURL
curl -I -X "OPTIONS" "http://search.o19s.com/" -H "Origin: http://app.o19s.com" HTTP/1.1 200 OK ... Access-Control-Allow-Origin: http://app.o19s.com
With the correct value in the responses’s
XMLHttpRequests will no longer be blocked by the browser.