Assets not loading when responding with another si...
# workers-help
l
So I have been trying to redirect
website2.com
under the`website.com/2` domain and so far I have managed to do that using the code:
Copy code
js
export default {
  async fetch(request) {
    async function MethodNotAllowed(request) {
      return new Response(`Method ${request.method} not allowed.`, {
        status: 405,
        headers: {
          Allow: "GET",
        },
      });
    }
    // Only GET requests work with this proxy.
    if (request.method !== "GET") return MethodNotAllowed(request);
    return fetch(`https://example.com`);
  },
};
It works fine but the assets are not loading and I get the plain html version of the website. I have setup the following worker routes: -
*dreamcafe.eu.org/assets/images*
-
*dreamcafe.eu.org/assets*
-
https://dreamcafe.eu.org/guides/
with the
*dreamcafe.eu.org/assets*
route it should make the website appear as normal but it doesn't does anyone know why?

https://cdn.discordapp.com/attachments/1107014041911689277/1107014208769499166/image.png

Console errors

https://cdn.discordapp.com/attachments/1107014041911689277/1107014475585958069/image.png

w
You aren't passing the path through there
So it's always just fetching the root
l
`*dreamcafe.eu.org/assets*`wouldn't this fix it?
w
No, you'd need to fetch with the path
l
oh in the worker and not the route? Lemme try
hmm it works in the preview now but the website throws a 404 errur.
Copy code
Page Not Found
Looks like you've followed a broken link or entered a URL that doesn't exist on this site.
Copy code
js
export default {
  async fetch(request) {
    async function MethodNotAllowed(request) {
      return new Response(`Method ${request.method} not allowed.`, {
        status: 405,
        headers: {
          Allow: "GET",
        },
      });
    }
    // Only GET requests work with this proxy.
    if (request.method !== "GET") return MethodNotAllowed(request);

    // Get the requested URL from the request object
    const url = new URL(request.url);

    // Extract the path from the URL and append it to the target URL
    const targetUrl = `https://example.com${url.pathname}`;

    // Fetch the target URL
    return fetch(targetUrl);
  },
};
I think I just don't fetch the /subdomain correctly now
I will look into it and I let you know
thnx for the help though
c
You've got
dreamcafe.eu.org/guides/
which is trying to fetch
example.com
with the same path, excluding /guides?
l
I am trying to fetch subdomain.example.com from example.com/subdomain
if you mean smth else please do let me know
c
So if a visitor is on example.com/subdomain/path, do you want the worker to fetch subdomain.example.com/subdomain/path, or subdomain.example.com/path
l
basically yes
so far I have only manage to fetch only the html part of it
I can't fetch the assets
even though I made a rule for it

https://cdn.discordapp.com/attachments/1107014041911689277/1107022160234565712/image.png

c
That question wasn't a yes or no question, usually when you want to fetch a subdomain from a path, you want to not preserve the path. The question is example.com/subdomain/path -> subdomain.example.com/subdomain/path or example.com/subdomain/path -> subdomain.example.com/path i.e do you want to keep the entire path, or trim off the subpath
Right now you're keeping the entire path
l
example.com/subdomain/path
rn I am using this code:
Copy code
js
export default {
  async fetch(request) {
    async function MethodNotAllowed(request) {
      return new Response(`Method ${request.method} not allowed.`, {
        status: 405,
        headers: {
          Allow: "GET",
        },
      });
    }
    // Only GET requests work with this proxy.
    if (request.method !== "GET") return MethodNotAllowed(request);

    // Get the requested URL from the request object
    const url = new URL(request.url);

    // Extract the path from the URL and append it to the target URL
    const targetUrl = `https://sub.example.com${url.pathname}${url.search}`;

    // Fetch the target URL
    return fetch(targetUrl);
  },
};
and in the preview it looks fine but I get a 404 error when I try to access it through the domain

https://cdn.discordapp.com/attachments/1107014041911689277/1107023694443851796/image.png

c
ahh ok, that's different from the code you sent above, that seems like you're trying to get
https://dreamcafe.eu.org/cookies.txt
to fetch something like
sub.dreamcafe.eu.org/cookies.txt
Can you share the actual domain names? Sounds like it's just your subdomain not responding with what you expect
l
sure
So I have the second website on the https://guides.dreamcafe.eu.org and I want to fetch it in https://dreamcafe.eu.org/guides
Copy code
js
export default {
  async fetch(request) {
    async function MethodNotAllowed(request) {
      return new Response(`Method ${request.method} not allowed.`, {
        status: 405,
        headers: {
          Allow: "GET",
        },
      });
    }
    // Only GET requests work with this proxy.
    if (request.method !== "GET") return MethodNotAllowed(request);

    // Get the requested URL from the request object
    const url = new URL(request.url);

    // Extract the path from the URL and append it to the target URL
    const targetUrl = `https://guides.dreamcafe.eu.org${url.pathname}${url.search}`;

    // Fetch the target URL
    return fetch(targetUrl);
  },
};
c
The real problem you're running into is the resources themselves are relative to the hostname, you can use html rewriter to rewrite most of them though, one sec
did you kill your guides subdomain? It's not loading for me anymore https://guides.dreamcafe.eu.org/
l
wdym?
they are loading for me
if you mean their content
they don't have any

https://cdn.discordapp.com/attachments/1107014041911689277/1107028511543283753/image.png

they are empty
c
nah it's just entirely blank for me, even on a vpn

https://cdn.discordapp.com/attachments/1107014041911689277/1107028589972574258/image.png

wasn't at first
l
hmmm
scroll down
do you see the html?
c
oh yea you killed the css
l
that's my issue
c
why do you have a worker running on there?
l
that was happening in my /subdomain also
at this point I have made so many changes I'd have to check
wait
does it work now?
(it does for me)
c
css now responds with the output of the example.com domain
is that domain fetching from another url too?
oh it's probably these routes
Copy code
*dreamcafe.eu.org/assets/images*
*dreamcafe.eu.org/assets*
l
yep
I deleted them
they will prob be updated in a few seconds
c
ahh ok now it's fine again
Your root issue is just that the assets on the guides subdomain use relative links, meaning even if you proxy the html to your /guides subpath, the resources aren't loaded from there
You can use a simplish worker with html rewriter to rewrite those links:
Copy code
javascript
const REAL_URL = "guides.dreamcafe.eu.org";
const FAKE_SUBPATH = "/guides";

export default {
  async fetch(request, env, ctx) {
    var url = new URL(request.url);
    url.hostname = REAL_URL;
    url.pathname = url.pathname.replace(FAKE_SUBPATH, "");

    var res = await fetch(url, request);

    const contentType = res.headers.get("Content-Type");
    // If the response is HTML, it can be transformed with
    // HTMLRewriter -- otherwise, it should pass through
    if (contentType.startsWith("text/html")) {
      return rewriter.transform(res);
    } else {
      return res;
    }
  },
};
// Used to rewrite link tags, img tags, etc
class AttributeRewriter {
  constructor(attributeName) {
    this.attributeName = attributeName;
  }
  element(element) {
    const attribute = element.getAttribute(this.attributeName);
    if (attribute) {
      element.setAttribute(this.attributeName, FAKE_SUBPATH + attribute);
    }
  }
}

// Rewriter
const rewriter = new HTMLRewriter()
  .on("a", new AttributeRewriter("href"))
  .on("base", new AttributeRewriter("href"))
  .on("link", new AttributeRewriter("href"))
  .on("img", new AttributeRewriter("src"));
The route you would need for that is just
dreamcafe.eu.org/guides*
l
(friendly reminder: because I can see I am using too much of your time you can leave at any point, sorry for doing that I am just very new to this)
c
no worries, you're all good. That simple html rewriter should be enough
l
I changed it... Can you check though? because I am still not getting the assets

https://cdn.discordapp.com/attachments/1107014041911689277/1107030350074499173/image.png

c
That worker is made to be on
/guides
with a route there. If you want your page to be under
/guides/
, change the FAKE_SUBPATH variable to
/guides/
l
yeah I want it under /guides
this one is fine
that's not the issue
do I need to add something to the worker routes?
(because I removed the routes I had before)
Copy code
*dreamcafe.eu.org/assets/images*
*dreamcafe.eu.org/assets*
these ones
c
ahh I see, I got confused a bit by what you said above. In the code I sent you, change
Copy code
js
const FAKE_SUBPATH = "/guides";
to
Copy code
js
const FAKE_SUBPATH = "/guides/";
As for the Worker Route, you just want one that is
dreamcafe.eu.org/guides/*
l
I still can't get the assets

https://cdn.discordapp.com/attachments/1107014041911689277/1107031960662056970/image.png

smh
😵‍💫
c
Might just need a second

https://cdn.discordapp.com/attachments/1107014041911689277/1107032087699140628/image.png

l
lemme load it on my phone
c
Shift+f5 usually does the trick as well
looks like the links/clicking on the blogs is broken on the subpath though, hmm
l
Maybe if we do that @Chaika

https://cdn.discordapp.com/attachments/1107014041911689277/1107032646967623680/image.png

https://cdn.discordapp.com/attachments/1107014041911689277/1107032693264367677/image.png

c
nah, that wouldn't do anything
l
Ok
c
That's just how we're appending the subpath onto the urls/removing it from the path of the request
l
Copy code
js
const REAL_URL = "guides.dreamcafe.eu.org";
const FAKE_SUBPATH = "/guides";

export default {
  async fetch(request, env, ctx) {
    var url = new URL(request.url);
    url.hostname = REAL_URL;
    url.pathname = url.pathname.replace(FAKE_SUBPATH, "");

    var res = await fetch(url, request);

    const contentType = res.headers.get("Content-Type");


    if (contentType.startsWith("text/html")) {
      return rewriter.transform(res);
    } else {
      return res;
    }
  },
};


class AttributeRewriter {
  constructor(attributeName) {
    this.attributeName = attributeName;
  }
  element(element) {
    const attribute = element.getAttribute(this.attributeName);
    if (attribute) {
      element.setAttribute(
        this.attributeName,
        `${FAKE_SUBPATH}/subdomain${attribute}`
      );
    }
  }
}

// Rewriter
const rewriter = new HTMLRewriter()
  .on("a", new AttributeRewriter("href"))
  .on("base", new AttributeRewriter("href"))
  .on("link", new AttributeRewriter("href"))
  .on("img", new AttributeRewriter("src"));
@Chaika would this fix it?
c
don't think so, a good try though. It looks like it's just because we're not transforming redirects to the guides subpath as well, a simple fix, one sec
a somewhat lazy monkeypatch that seems to work fine in all conditions:
Copy code
js
const REAL_URL = "guides.dreamcafe.eu.org";
const FAKE_SUBPATH = "/guides";

export default {
  async fetch(request, env, ctx) {
    var url = new URL(request.url);
    url.hostname = REAL_URL;
    url.pathname = url.pathname.replace(FAKE_SUBPATH, "");

    var res = await fetch(url, request);
    const newResponse = new Response(res.body, res);
     // transform redirects as well
    if (newResponse?.headers?.get("Location")) {
      newResponse.headers.set("Location", FAKE_SUBPATH + res.headers.get("Location"));
    }
    const contentType = res.headers.get("Content-Type");
    // If the response is HTML, it can be transformed with
    // HTMLRewriter -- otherwise, it should pass through
    if (contentType.startsWith("text/html")) {
      return rewriter.transform(newResponse);
    } else {
      return newResponse;
    }
  },
};
// Used to rewrite link tags, img tags, etc
class AttributeRewriter {
  constructor(attributeName) {
    this.attributeName = attributeName;
  }
  element(element) {
    const attribute = element.getAttribute(this.attributeName);
    if (attribute) {
      element.setAttribute(this.attributeName, FAKE_SUBPATH + attribute);
    }
  }
}

// Rewriter
const rewriter = new HTMLRewriter()
  .on("a", new AttributeRewriter("href"))
  .on("base", new AttributeRewriter("href"))
  .on("link", new AttributeRewriter("href"))
  .on("img", new AttributeRewriter("src"));
l
seems to be working
thank you very much
sry for wasting your time
I just found out about workers today and lets say they are different from the simple discord bots and websites I am used to making
c
you're fine, not a waste, the power of Workers (at least in my opinion) lies in the fact you can do transformations like this, and Workers run in every one of Cloudflare's 350+ colos, so you're not majorly slowing everything down or adding much latency
s
@Chaika For me the assets are loading, but there seems to be a parsing error somewhere: My usecase it to use cloudflare workers as a reverse proxy to http://domain.example.com to example.com/.
Copy code
export default {
  async fetch(request: {
    url: string | URL; headers: { get: (arg0: string) => string } 
}, env: any, ctx: any) {
    try {
      const subdomain = request.headers.get('host').split('.')[0];
      const id = mapSubdomainToId(subdomain);
      const destinationURL = new URL(`http://localhost:3001/${id}`);
      return fetch(destinationURL);
    } catch (error) {
      return new Response(null, { status: 404, statusText: "Oops can't find that page" });
    }
  },
};
For now I'm running this on wrangler locally, so need to proxy to localhost:3001, which is a next.js site.

https://cdn.discordapp.com/attachments/1107014041911689277/1112257012777111573/image.png