Rails Custom Response Headers
I want to set custom headers in the response within my Rails application. This is a “secret channel” to communicate additional information within the web request.
If you would like to follow along:
Once cloned, run:
$ vagrant up to create the Virtualbox that canrun
After the Virtualbox finishes building, run:
$ vagrant ssh to log
into the virtualbox computer and to get to the project resources, run
Run the sample_app
The vagrant script sets up a
sample_app in the
folder. This is a clean Rails app and we will use to check how
things work in a pristine environment.
I have never had to examine HTTP headers before, but these headers are everywhere! With every request, the server adds headers and are transparent to the web experience.
There are two way to see headers: through the web browser and curl. I will show how both works to verify the same headers are coming through both.
In a web browser like Chrome, or in my case,
Vivaldi, on the page, open up the Inspector
from the right menu command or opening the menu option:
$ curl -I
Another option I like is to use the
$ curl command. To have the curl
command only return headers, use the
-I option (note: capital i,
not a lowercase l):
The details are equivalent between the
$ curl command and the
browser details, except presentation format.
For the remainder of the article, I will use the curl command instead
of the web browser. It’s just easier to display
$ curl output
instead of browser output.
Let’s make a new controller to receive a request:
To make the new
/test endpoint accessible, we must make an entry to
Add index to controller
The controller needs the corresponding method specified in the
routes.rb file, which is an
Let’s make sure the new endpoint is working by checking its response:
Now let’s check its headers with
$ curl -I:
Cool, pretty straight forward.
Custom Header in Test
To add just a header into the
/test controller, add the desired
response.headers field in the following format:
As a convenience, using an
after_action for the controller will add
the desired header to every endpoint supported by that controller:
1 2 3 4 5 6 7 8 9 10 11 12 class TestController < ApplicationController after_action :add_headers def index render json: 'test' end def add_headers response.headers['test-controller-header'] = 'test-controller-header-value' end end
To see the new headers, use
$ curl -I command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 vagrant@ubuntu-xenial:~$ curl -I localhost:3000/test HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff X-Download-Options: noopen X-Permitted-Cross-Domain-Policies: none Referrer-Policy: strict-origin-when-cross-origin Content-Type: application/json; charset=utf-8 test-controller-header: test-controller-header-value ETag: W/"9f86d081884c7d659a2feaa0c55ad015" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: e456d916-2b19-4b00-a107-83087bde7e1a X-Runtime: 0.008259
The new header:
test-controller-header shows up on line 10.
The relevant line:
Custom Header Every Endpoint
To have custom headers on every controller, add a similar function
Test again using:
$ curl -I command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 vagrant@ubuntu-xenial:~$ curl -I localhost:3000/test HTTP/1.1 200 OK X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff X-Download-Options: noopen X-Permitted-Cross-Domain-Policies: none Referrer-Policy: strict-origin-when-cross-origin Content-Type: application/json; charset=utf-8 test-controller-header: test-controller-header-value X-Every-Endpoint-Custom-Headers: every endpoint custom header value ETag: W/"9f86d081884c7d659a2feaa0c55ad015" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: ea1752cd-6831-4eb5-9382-8efde4c423f6 X-Runtime: 0.105045
On line 11, the
X-Every-Endpoint-Custom-Headers appears with the
test-controller-header on line 10. The former is from the
application_controller and the latter is from the
The relevant parts:
Setting up Rails to have a “secret channel” for communicating
information in a response is easy. Modify the
object from the controller.
Adding information to every controller is as easy as modifying the
response.headers object from the
I will take advantage of this feature whenever I need to have a “secret channel” in the server response.