Speeding up CORS preflight requests with Cloudflare Workers

As a security measure browsers perform CORS preflight requests, but sometimes those preflight requests add significant latency - for example if your CORS-enabled API is hosted in single location and you have users all across the world. Some users located far away from your API server might need to wait extra 200-300ms to just get CORS response.

This can be improved by routing all OPTIONS requests to Cloudflare Worker that should respond quickly no matter where your users are.

In my case it didn’t make sense to route all API traffic through Cloudflare worker (which can be done using its fetch method). With suggested solution only OPTIONS requests are handled by the worker, other traffic is handled directly by the API.

Following diagram shows what we are trying to achieve:

B r o w s e r O P 2 T 0 I 4 O N R S e s R p e o q n u s e e C s l t o 2 P 2 u G 0 O 0 d E 0 S 0 f T T l R R a R e R e r e s e s e q p q p u o u o W e n e n o s s s s r t e t e k e r A P I S e r v e r

With this setup we get benefit of faster CORS requests, but at the same time we are not adding extra latency by proxying every request.

Cloudflare doesn’t have direct way to connect worker just for specfiic HTTP method, so we need to workaround it using page rules.

Step 1. Create worker

First you need to create Cloudflare Worker. It doesn’t need to have custom domain as we won’t be using it directly.

This is simplest version that just returns Access-Control-Allow-Origin header.

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
  "Access-Control-Allow-Headers": "*",
};

export default {
  async fetch(request, env, ctx) {
    if (request.method === "OPTIONS") {
      return new Response(null, {
        status: 204,
        headers: corsHeaders,
      });
    }

    return new Response("Proxy is working. Will respond to OPTIONS");
  },
};

To create worker in Cloudflare account dashboard:

  1. Go to Compute (Workers).
  2. Click Create.
  3. Select Hello World template.
  4. Pick some worker name and click Deploy.
  5. Click Edit code.
  6. Use worker code from above and click Deploy.

Step 2. Create rule to redirect OPTIONS requests to /cors-proxy

We will redirect all OPTIONS requests to some path on your domain. Exact path isn’t really important as we will just use it to connect worker in later steps.

In Cloudflare dashboard for you domain:

  1. Go to Rules.
  2. Click Create rule.
  3. Select URL Rewrite Rule.
  4. Use following rule details:
    1. Rule name: Rewrite OPTIONS request to /cors-proxy
    2. If incoming requests match…: Custom filter expression
    3. Use two fields with AND operator:
      • Hostname - equals - api.example.com
      • Request Method - equals - OPTIONS
    4. Then…:
      1. Path - rewrite to - static - /cors-proxy
      2. Query - preserve
  5. Click Save.

With this change all OPTIONS requests will be forwarded to api.example.com/cors-proxy. This isn’t really useful on itself, but with this rule we can now connect our worker to this path.

Step 3. Create Worker Route to connect your worker

Again, in Cloudflare dashboard for your domain:

  1. Go to Workers Routes.
  2. Click Add route.
  3. Fill it in as:
    • Route: api.example.com/cors-proxy
    • Worker: Select worker you created in step 1.
  4. Click Save.

Step 4. Enjoy faster CORS requests

You can now enjoy the results. Because preflight requests don’t ever hit your actual API and are served by worker you will get good response times for those requests regardless where you access it from as they run on Cloudflare’s edge network.

Before:

Preflight response times without worker

After:

Preflight response times with worker