Gulzar
Gulzar

Reputation: 27896

How to hide webapi url and show a "pretty" url?

I need to generate a pretty URL for my own URL shortening service.
My web server address looks something like https://my-backend-api-server.us-central1.run.app/redirectapp/redirect/wAzclnp3

and I wouldn't want to expose that, nor is it short.

Assuming I have a domain www.mydomain123.com, I want to "prettify" my URLs so that www.mydomain123.com/wAzclnp3 will serve https://my-backend-api-server.us-central1.run.app/redirectapp/redirect/wAzclnp3 and www.mydomain123.com or www.mydomain123.com/otherapp will serve from my webserver (not the api server)

How to do this in django ?

Upvotes: 1

Views: 40

Answers (1)

Gulzar
Gulzar

Reputation: 27896

I ended up using a reverse proxy as suggested by @grawity_u1686

I set up a worker in CloudFlare.com (and locally with wrangler) The code (which was more complex than I had hoped) is following. I had to also support assets, and change my backend to only return the hash itself and not a redirect object.

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

async function handleRequest(request) {
    const url = new URL(request.url);
    const path = url.pathname;

    console.log(`Incoming request URL: ${url}, Path: ${path}`);

    // Handle /r/{somehash} redirects
    if (path.startsWith('/r/')) {
        const hash = path.substring(3); // Extract "somehash" from "/r/{somehash}"
        
        const backendUrl = `https://backend-1234.us-central1.run.app/app/unhash/${hash}`;
        
        try {
            console.log(`Fetching URL from backend: ${backendUrl}`);

            // Fetch the URL from the backend
            const response = await fetch(backendUrl, {
                method: 'GET',
                headers: request.headers,
            });

            if (!response.ok) {
                throw new Error(`Backend responded with status ${response.status}`);
            }

            console.log(response);

            const data = await response.json();
            const resolvedUrl = data.long_url;

            if (!resolvedUrl) {
                throw new Error('No URL found in backend response');
            }

            console.log(`Resolved URL from backend: ${resolvedUrl}`);

            return Response.redirect(resolvedUrl, 302);
        } catch (error) {
            console.error(`Error resolving /r/${hash}: ${error.message}`);
            return new Response(`Error resolving the redirect: ${error.message}`, {
                status: 502,
                headers: { 'Content-Type': 'text/plain' },
            });
        }
    }

    // Handle static file requests
    if (path.startsWith('/static/') || path.startsWith('/assets/')) {
        const staticUrl = `https://myaccount.github.io/personal_website${path}`;
        try {
            const staticResponse = await fetch(staticUrl, {
                method: 'GET',
                headers: request.headers,
                redirect: 'follow',
            });

            if (!staticResponse.ok && staticResponse.status !== 404) {
                throw new Error(`Static file fetch failed with status ${staticResponse.status}`);
            }

            return staticResponse;
        } catch (error) {
            console.error(`Error fetching static file: ${error.message}`);
            return new Response(`Error fetching static file: ${error.message}`, {
                status: 502,
                headers: { 'Content-Type': 'text/plain' },
            });
        }
    }

    // Default behavior: Proxy other requests to GitHub Pages
    const githubUrl = `https://myaccount.github.io/personal_website${path}`;
    try {
        let response = await fetch(githubUrl, {
            method: request.method,
            headers: request.headers,
            body: request.method !== 'GET' && request.method !== 'HEAD' ? request.body : null,
            redirect: 'follow',
        });

        if (response.status === 404) {
            // Serve index.html for client-side routing
            const indexUrl = `https://myaccount.github.io/personal_website/index.html`;
            response = await fetch(indexUrl, {
                method: 'GET',
                redirect: 'follow',
            });
        }

        // Clone and modify headers
        let newHeaders = new Headers(response.headers);
        newHeaders.set('Access-Control-Allow-Origin', '*');

        return new Response(response.body, {
            status: response.status,
            statusText: response.statusText,
            headers: newHeaders,
        });
    } catch (error) {
        console.error(`Error fetching GitHub Pages: ${error.message}`);
        return new Response(`Error fetching GitHub Pages: ${error.message}`, {
            status: 502,
            headers: { 'Content-Type': 'text/plain' },
        });
    }
}

Upvotes: 0

Related Questions