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?
When an 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 Origin: http://app.o19s.com/
.
At this point the server should respond with a pair of headers, Access-Control-Allow-Origin
and Access-Control-Allow-Methods
. The 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 Access-Control-Allow-Methods
.
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.
-
Verify the
server/webapps/solr.war
file is extracted toserver/solr-webapp/webapp
. If not this may be accomplished with the following commands# Server is the directory where Solr resides
cd server
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/lib
directory -
Edit the
server/solr-webapp/webapp/WEB-INF/web.xml
file to include the following filter right after theline. 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
allowedOrigins
value here is*
which permits access from all origins. Consider setting this value to the domain where your application is hosted (ex:app.o19s.com
). TheallowedMethods
param may also be trimmed to just the methods needed by your application (ex:GET,POST
). - 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 Access-Control-Allow-Origin
header XMLHttpRequest
s will no longer be blocked by the browser.