CloudFlare Workers - Check for Cookie, Add Headers, Set Cookie
Asked Answered
S

2

9

I want to dynamically add http-headers via CloudFlare workers ONLY for the first time visitors. For example these headers:

Link: </path/to/file.css>; rel=preload; as=style; nopush
Link: </path/to/script.js>; rel=preload; as=script; nopush

So, what I need is the following, via JavaScript, in CloudFlare Workers:

  1. Check if a specific cookie exists on the client's side.
  2. If the cookie doesn't exist add http-headers and then set that specific cookie.
  3. If the cookie does exist do nothing.

You can play with the code here.

Here's a general example (involving cookie and headers) from the CF's blog:

// A Service Worker which skips cache if the request contains
// a cookie.
addEventListener('fetch', event => {
  let request = event.request
  if (request.headers.has('Cookie')) {
    // Cookie present. Add Cache-Control: no-cache.
    let newHeaders = new Headers(request.headers)
    newHeaders.set('Cache-Control', 'no-cache')
    event.respondWith(fetch(request, {headers: newHeaders}))
  }

  // Use default behavior.
  return
})
Sorrel answered 22/3, 2018 at 12:31 Comment(1)
It's a bit disappointing that no one has opinion about this.Sorrel
M
21

Here's a Cloudflare Worker that implements what you describe:

addEventListener('fetch', event => {
  event.respondWith(handle(event.request))
})

async function handle(request) {
  // Check for cookie.
  let cookies = request.headers.get('Cookie') || ""
  if (cookies.includes("returning=true")) {
    // User has been here before. Just pass request through.
    return fetch(request)
  }

  // Forward request to origin, get response.
  let response = await fetch(request)

  // Copy Response object so that we can edit headers.
  response = new Response(response.body, response)

  // Add headers.
  response.headers.append("Link",
      "</path/to/file.css>; rel=preload; as=style; nopush")
  response.headers.append("Link",
      "</path/to/script.js>; rel=preload; as=script; nopush")

  // Set cookie so that we don't add the headers
  // next time.
  response.headers.set("Set-Cookie", "returning=true")

  // Return on to client.
  return response
}
Multiversity answered 23/3, 2018 at 22:32 Comment(2)
Works like a charm.I have another question: Let say a WordPress website has this header cache-control: public, max-age=1800. Modify the above worker script so this header is removed when following cookies are present wp-.*|wordpress.*|comment_.* meaning when a user is logged in and/or have commented on the website. Note the asterisks, those are not full cookie names. Also this rule needs to be applied only on html pages. I don't want cache-control header stripped for the static resources (images. css, script, etc.).Sorrel
When I said 'modify' the script I meant add this new condition to the script.Sorrel
S
3

I've managed to modify the worker and provide a solution where Cache-Control header is removed if the user has commented on the website.

addEventListener('fetch', event => {
    event.respondWith(addHeaders(event.request))
})

async function addHeaders(request) {
    // Forward request to origin, get response.
    let response = await fetch(request)

    if (response.headers.has("Content-Type") && 
        !response.headers.get("Content-Type").includes("text/html")) {
        // File is not text/html. Pass request through.
        return fetch(request)
    }

    // Copy Response object so that we can edit headers.
    response = new Response(response.body, response)

    // Check for cookie.
    let cookies = request.headers.get('Cookie') || ""
    if (cookies.includes("returning=true")) {

        if (cookies.includes("comment_") && response.headers.has("Cache-Control")) {
            // User has commented. Delete "cache-control" header.
            response.headers.delete("Cache-Control")

            // Return on to client.
            return response
        }

        // User has been here before but has not commented.
        // Just pass request through.
        return fetch(request)
    }

    // Add headers.
    response.headers.set("Link", 
        "</path/to/file.css>; rel=preload; as=style; nopush")
    response.headers.append("Link", 
        "</path/to/script.js>; rel=preload; as=script; nopush")

    // Set cookie so that we don't add the headers next time.
    response.headers.set("Set-Cookie", "returning=true")

    // Return on to client.
    return response
}

However, if you're trying to delete a header which is set by Cloudflare in the first place (in this case Cache-Control) you'll encounter an unknown error 1101 which will make your site inaccessible. Also you can't modify a header set by Cloudflare. Apparently you can ONLY manipulate headers set by origin and eventually add new headers.

Sorrel answered 26/3, 2018 at 15:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.