CORS, proxies, and the trailing slash issue

TL;DR On the client side, use trailing slash when requesting the “default” resource from a Flask app.

Server:

# Python flask server at /var/www/api/myapp
app = Flask(__name__)

@app.route('/')
def get_root_resource():
    ...
    return xyz

Client:

// Javascript client
const response = await fetch("/api/myapp/); // note the trailing slash

Why it matters

In Production

If you make a request without the trailing slash, e.g. https://myserver.com/api/myapp, the server would redirect it 308 PERMANENT REDIRECT to https://myserver.com/api/myapp/, with a trailing slash.

In production settings, when both the client and the Flask app are served from the same domain, it is just a performance issue: there is an additional network round-trip for each API request. The sequence of events in production is:

  1. Client makes request to https://myserver.com/api/maypp
  2. Server responds with 308 PERMANENT REDIRECT to https://myserver.com/api/maypp/
  3. Client makes request to https://myserver.com/api/maypp/
  4. Server responds with the data.

In Development

In development settings omitting the final slash may cause CORS problems. My scenario was as follows.

The client is a React application. In debug mode, I serve it from the npm development server (npm start) at http://localhost:3000/. If the client makes an explicit request to https://myserver.com/api/myapp, it causes a CORS error, unless the API is configured to accept any origin (which it isn’t).

To avoid that, we setup a proxy in package.json (documentation), so the npm development server picks up requests to /something, and fetches data from https://myserver.com/something behind the scenes. This bypasses the CORS checker: as far as the browser is concerned, we never go out to myserver.com and receive everything from localhost.

{
  "name": "myclient",
  "version": "0.1.0",
  "proxy": "https://myserver.com",
  "private": true,
  ...
}

The sequence of events then becomes:

  1. Client makes request to /api/maypp.
  2. Local npm server forwards the request to https://myserver.com/api/maypp
  3. Remote server responds with 308 PERMANENT REDIRECT to https://myserver.com/api/maypp/
  4. Client makes request to https://myserver.com/api/maypp/
  5. This causes a CORS error in the browser, since the client is on localhost and we are requesting data from a different domain.

If the client makes a request to /api/myapp/ with trailing slash included, everything works as expected:

  1. Client makes request to /api/maypp/
  2. Local npm server forwards the request to https://myserver.com/api/maypp/
  3. Remote server responds with the data, no redirect needed.
  4. Client gets the data, no CORS errors.

So, that little trailing slash matters, don’t forget to include it.

Leave a Reply

Your email address will not be published. Required fields are marked *