Worker - Redirecting /* to /ajax/libs/*

ExpertTip

#1

Hi guys,

Could someone have a read over this code I’ve written for a worker and confirm if it does what I think it should do? I have never used workers before so this is completely new to me.

This code should redirect any path that doesn’t start with “/ajax/libs” so that it will be prefixed with “/ajax/libs”.

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

function fetchAndApply(request) {
  const requestURL = new URL(request.url)
  if(!requestURL.pathname.startsWith("/ajax/libs")) requestURL.pathname = "/ajax/libs" + requestURL.pathname
  return fetch(requestURL.toString(), request)
}

Thanks,
Matt.
CM @ cdnjs


#2

Should work!

The only thing is that the .toString() in the return shouldn’t be needed.


#3

Ah okay, does fetch take a URL object okay? I saw from examples strings were normally passed as the first argument?


#4

It works both ways, an URL object works, a string works as well. It simply adds a piece of code that is not needed, can work with it, but less code is usually always better.


#5

Late arrival.

function fetchAndApply(request) {
  const requestURL = new URL(request.url)
  if(!requestURL.pathname.startsWith("/ajax/libs")) 
    { 
    requestURL.pathname = "/ajax/libs" + requestURL.pathname
    }
  return fetch(requestURL)
}

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

#6

Any reason for adding the curly brackets back in? Just extra bytes that aren’t needed?
And does the original request not need to be passed back into fetch? The Cf examples seemed to always do it?


#7

As far as I know the brackets are just extra, the request in the fetch helps with all the various headers and eventual cookies or body if it’s a POST, it’s usually best practice to keep unless you really don’t want it.

Maybe @adaptive has a reason I don’t know.


#8

{ } is just part of secret society demand. @matteo @matthew
If the task was GET .js… files from a specific path, I was filtering out POST, for security reasons.


#9

You aren’t really filtering them out as much as rewriting them to GET. You need to filter them explicitly.


#10

Do you know how I could make this only rewrite requests that 404 with their original path to then go to /ajax/libs @matteo ? I don’t want to make content at the root inaccessible if possible.

(I don’t actually know if there is content at root, I’m just wanting to make this fail-safe when Cloudflare deploy it for us).


#11

Will write you a piece of code in a few minutes, but basically you would do the request with the default URL, check the status code of the response, if 200 then return, otherwise change path and redo the request which returns anyway.


#12
addEventListener('fetch', event => {
  event.respondWith(fetchAndApply(event.request))
})

async function fetchAndApply(request) {
  const requestURL = new URL(request.url)
  if(!requestURL.pathname.startsWith("/ajax/libs")) {
    const requestResponse = await fetch(request)
    if(requestResponse.status !== 200) requestURL.pathname = "/ajax/libs" + requestURL.pathname
  }
  return fetch(requestURL, request)
}

Trying my best to learn this myself as I already know some JS but workers are new to me.
I think this should do it correctly?

Should I use an else after the status if and return requestResponse so that I’m not making a double fetch?


#13

Not really, the idea is correct, but your doubt here is sort of correct.

You aren’t returning the first response anywhere. You would need to add an else as you said. I would probably do the reverse: do if == 200 => return, this ends the execution of the Worker (unless you use the .waitUntil() method), no else and then continue as you wrote. Like this.

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

async function fetchAndApply(request) {
  const requestURL = new URL(request.url)
  if(!requestURL.pathname.startsWith('/ajax/libs')) {
    const requestResponse = await fetch(request)
    if(requestResponse.status == 200) return constResponse
    requestURL.pathname = '/ajax/libs' + requestURL.pathname
  }
  return fetch(requestURL, request)
}

PS: use consistently ' and ", corrected them above.


#14

Awesome, thank you very much for the help. Now to wait for Cf to deploy this.


#15

It’s basically instant! No worries about that.

You are from cdnjs.com, right?


#16

Unfortunately we have no access to cdnjs.cloudflare.com so I’ll have to wait in a support ticket to get it deployed.

Indeed, I am. :slight_smile:


#17

Understandable, it’s their subdomain. Why not something like cdn.cdnjs.com or something, so it’s under your domain, but still on Cloudflare?


#18

This was setup way before my time, I don’t want to rock the boat as we now serve roughly something like 5 billion requests a day through that domain.


#19

5 billion?! Wow. It would be cool seeing some stats, even some basic ones! I often have used the service. Thanks for it!


#20

Don’t hold me to that number, I think its roughly right though.

I’ll see if I can find stats from our previous tickets.