getAssetFromKV not running mapRequestToAsset

Hi,

My goal is to return the contents of file ‘/error/500.html’ with a HTTP status code of 500 when my code enters a javascript catch block.

The approach is to use getAssetFromKV to get the page contents, along the lines of the example “handlePrefix”.

The problem I’ve got is that I’m still returning the original page contents (with a 500 status), rather than the error page contents.

The function I’m expecting to be used as mapRequestToAsset is:

function serve500Page() {
    return request => {
        console.log("Running serve500Page...");

        // compute the default (e.g. / -> index.html)
        let defaultAssetKey = mapRequestToAsset(request)
        let url = new URL(defaultAssetKey.url)

        // strip the prefix from the path for lookup
        url.pathname = "/error/500.html";

        // inherit all other props from the default request
        return new Request(url.toString(), defaultAssetKey)
    }
}

The call to getAssetFromKV is:

let notFoundResponse = await getAssetFromKV(event, {
    mapRequestToAsset: serve500Page(),
    cacheControl: { bypassCache: true, },
});

let resp = new Response(notFoundResponse.body, { ...notFoundResponse, status: 500 });

console.log("Response body is: " + await resp.text());

Using wrangler to tail the logs, I don’t ever see the output from

“console.log(“Running serve500Page…”);”

The output for response body is:

[“Response body is: <!doctype html>\n\n \n <link rel=“icon” type=“image/x-icon” href=“favicon.ico”>\n\n \n \nPage 3, with some more text\n \n”]

Which is the text of the originally requested page.

Can anyone spot/suggest what I’m doing wrong?

I’m pretty new to Workers Sites (and quite rusty with JavaScript) so I’m likely just being dim…

Cheers, Andy

I think I’ve figured out what’s going on…

In the source for getAssetFromKV from around line 101 there is:

const rawPathKey = new URL(request.url).pathname.replace(/^/+/, ‘’) // strip any preceding /'s
let pathIsEncoded = false
let requestKey
if (ASSET_MANIFEST[rawPathKey]) {
requestKey = request
} else if (ASSET_MANIFEST[decodeURIComponent(rawPathKey)]) {
pathIsEncoded = true;
requestKey = request
} else {
requestKey = options.mapRequestToAsset(request)
}

It looks like mapRequestToAsset is executed only if the originally requested asset isn’t found in the site asset KV namespace (via a lookup in the site manifest), which makes sense for some scenarios (perhaps a static site generator adding some extraneous root dir to all paths within a site) but not for scenarios where you want to send a different page even though the original page exists (my current example is to send a different page back to the browser if the request has a missing or invalid authentication token).

To address the cases where I need to return an alternative page (that is also an asset in the workers site and so present in the site manifest and the site asset KV namespace) I’m using this function:

async function fetchSiteAssetFromKv(assetPath) {
    let response;

    //console.log("fetchSiteAssetFromKv - Looking for asset: " + assetPath);

    const siteAssetPath2KvKey = JSON.parse(__STATIC_CONTENT_MANIFEST);

    const pageKey = siteAssetPath2KvKey[assetPath];
    //console.log("fetchSiteAssetFromKv - Asset: " + assetPath + " has page key: " + pageKey);

    if (pageKey) {
    
    const body = await __STATIC_CONTENT.get(pageKey, 'arrayBuffer');

    if (body === null) {
        throw "Null asset found in __STATIC_CONTENT for: " + assetPath;
    }

    response = new Response(body);

    } else {
    throw "No entry in site manifest for asset path: " + assetPath;
    }

    return response;
}

This seems to work fine, though I don’t yet understand how __STATIC_CONTENT_MANIFEST and __STATIC_CONTENT get set up…