Redirecting worker not redirecting :-(


#1

I am experimenting in the sandbox a worker that is supposed to redirect requests based on user agent. The idea is that we let the request pass most of the cases, while in some situations, we add a querystring to the URL.

The worker intercepts http://ic-editor-staging.hcms.me/ and the code of the worker is at the end of this email.

There are a few things that puzzle me:

  • I see in the console that there are 4 requests processed (one for my target url and 3 for CSS files that belong to my page). I imagine that during the worker execution there is time for my browser to request also pieces of the page, beyond the root url. OK, but still I ask myself where are the requests for all the other static files in the page? This point is not really clear to me. I try with google.com and I see that there are approx 10 requests in the console: the main page and 9 static files.

  • My code switches between two urls to fetch, as the code shows: one is the same url requested by the user, the second (only for selected user agents) is again the same, but with a querystring attached.

What I verify in the sandbow window is that the page actually fetched in the second case is still the first one, just as the querystring parameters were ignored.

Am I doing something wrong? I hope someone is able to shed some light.


WORKER CODE

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

async function fetchAndApply(request) {

const requestUrl = ''+ request.url;

if (requestUrl[requestUrl.length - 1] !== '/') {
  console.log('fetching right away:', requestUrl);
  return fetch(request); 
}

console.log('requestUrl input', requestUrl);

let suffix = ''

const chromeMarco = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36';

// Check for a custom header sent by the client
if (request.headers.get('user-agent') === chromeMarco) {
  suffix = '?ic=http://dev.dev103.social-net.me:8081/imagecreator/dynImageAPI.php?apiKey=sp8WyBm85uqQfsR47xEqRKsMV44Hvrsa&background_type=pseudoImage&background_pseudoString=canvas%3Awhite&nullTemplate=y&lang=en&objectOrder=textbox0&resol=1200x630&textbox0_x=50&textbox0_y=50&textbox0_w=400&textbox0_h=100&textbox0_text=Lorem+ipsum+dolor+sit+amet...&textbox0_align=L&textbox0_font=17&textbox0_fontColor=%23000000FF&textbox0_maxFontSize=96&textbox0_valignMethod=v&textbox0_valign=C&textbox0_effect=null'
}

const init = {
  method: request.method,
  headers: request.headers
}

console.log('fetching',requestUrl + suffix);

const modifiedRequest = new Request(requestUrl + suffix, init);
return fetch(modifiedRequest);

}


#2

Hi @marco_faustinelli,

The worker preview is not a completely accurate representation of what will happen when a worker script is deployed – there are some technical limits where we just make the best effort we can. Intercepting subrequests in the preview and directing them through the worker script being developed is one of these limits.

The four requests that you are seeing are likely the only four subresources that are linked to from the HTML document directly. All of the other requests that you expect to see, but don’t, are probably either:

  • On a different domain, e.g. fonts.gstatic.com, which would not normally be intercepted by your worker.

  • Initiated with XHR/fetch from the JS payload that was downloaded.

Now, some of those XHR/fetch requests may be intercepted. Specifically, if the request uses a relative URL, e.g. fetch("/foo"), then it should naturally work. If the request uses an absolute URL, then we cannot intercept it, so you won’t see it logged from your worker.

Moreover, if a request is to an http://... URL, then it probably won’t even escape the browser: fetching a resource over http from an https site (like the workers preview) breaks Chrome’s mixed content policy. This is definitely happening in your case. To see the error messages from this, try using the preview with the browser’s own DevTools console open – you should see some error messages printed to this effect.

The query string that you add will only be visible to the origin server, not the browser. Could it be that your web app changes its state based on the query string on the browser side? If so, you’ll need to expose the new URL, with query string, by returning an actual redirect, e.g. instead of:

  const modifiedRequest = new Request(requestUrl + suffix, init);
  return fetch(modifiedRequest);

use:

  return Response.redirect(requestUrl + suffix)

Unfortunately, this is all but guaranteed not to work in the preview: since Cloudflare Workers don’t have a script URL like a browser-side Service Worker (e.g., https://example.com/sw.js), we cannot give relative URLs to Response.redirect(), but must use an absolute URL, so at the very least we run into the https/http mixed content problem that I described above.

Since the preview breaks down for your use case, I recommend fully deploying your script to your staging domain in order to test it.

The original text above was incorrect – returning a redirect from a worker under preview should work as expected.

Let me know if you have any more questions!
Harris


#3

Correction! Returning a redirect from a worker being previewed should not break the preview – it should work as expected, including in this case. In light of that, it might be worthwhile giving my Response.redirect() suggestion a try. In fact, if you are able to switch your web app’s browser-side XHR/fetch requests to use relative URLs, the entire thing may just work.


#4

Hello Harris,
Thank you very much for the extensive answer. Things are now working very well.
Cheers,
Marco


#5

@marco_faustinelli, glad to hear it, and glad to help!


#6

Thanks @harris this solved it for me too. I recommend we add something in the docs to represent these redirect scenarios.