Accessing the cf object in a React app

I am new to cloulflare, and even in web development in general.
In an already functional application in React, I successfully configured and published the application on CF:
https://developers.cloudflare.com/workers/tutorials/deploy-a-react-app-with-create-react-app

Current worker script:


import {
    getAssetFromKV,
    mapRequestToAsset,
} from "@cloudflare/kv-asset-handler";

/**
 * The DEBUG flag will do two things that help during development:
 * 1. we will skip caching on the edge, which makes it easier to
 *    debug.
 * 2. we will return an error message on exception in your Response rather
 *    than the default 404.html page.
 */
const DEBUG = true;

addEventListener("fetch", (event) => {
    try {
        event.respondWith(handleEvent(event));
    } catch (e) {
        if (DEBUG) {
            return event.respondWith(
                new Response(e.message || e.toString(), {
                    status: 500,
                })
            );
        }
        event.respondWith(new Response("Internal Error", { status: 500 }));
    }
});

async function handleEvent(event) {
    const url = new URL(event.request.url);
    let options = {};

    /**
     * You can add custom logic to how we fetch your assets
     * by configuring the function `mapRequestToAsset`
     */
    // options.mapRequestToAsset = handlePrefix(/^\/docs/)
    options.mapRequestToAsset = (req) => {
        // First let's apply the default handler, which we imported from
        // '@cloudflare/kv-asset-handler' at the top of the file. We do
        // this because the default handler already has logic to detect
        // paths that should map to HTML files, for which it appends
        // `/index.html` to the path.
        req = mapRequestToAsset(req);

        // Now we can detect if the default handler decided to map to
        // index.html in some specific directory.
        if (req.url.endsWith("/index.html")) {
            // Indeed. Let's change it to instead map to the root `/index.html`.
            // This avoids the need to do a redundant lookup that we know will
            // fail.
            return new Request(`${new URL(req.url).origin}/index.html`, req);
        } else {
            // The default handler decided this is not an HTML page. It's probably
            // an image, CSS, or JS file. Leave it as-is.
            return req;
        }
    };

    try {
        if (DEBUG) {
            // customize caching
            options.cacheControl = {
                bypassCache: true,
            };
        }
        const page = await getAssetFromKV(event, options);

        // allow headers to be altered
        const response = new Response(page.body, page);

        response.headers.set("X-XSS-Protection", "1; mode=block");
        response.headers.set("X-Content-Type-Options", "nosniff");
        response.headers.set("X-Frame-Options", "DENY");
        response.headers.set("Referrer-Policy", "unsafe-url");
        response.headers.set("Feature-Policy", "none");

        return response;
    } catch (e) {
        // Fall back to serving `/index.html` on errors.
        return getAssetFromKV(event, {
            mapRequestToAsset: (req) =>
                new Request(`${new URL(req.url).origin}/index.html`, req),
        });
    }
}

/**
 * Here's one example of how to modify a request to
 * remove a specific prefix, in this case `/docs` from
 * the url. This can be useful if you are deploying to a
 * route on a zone, or if you only want your static content
 * to exist at a specific path.
 */
function handlePrefix(prefix) {
    return (request) => {
        // 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 = url.pathname.replace(prefix, "/");

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

Now I try, without success, to access the cf object, next to or in the above worker.
https://developers.cloudflare.com/workers/examples/accessing-the-cloudflare-object
I would like to extract in my application, and to consume the data longitude, latitude … etc.

Can someone help me or direct me to the right documentation ?!
thank you!

If you could format your code nicely into a code block that would be great. Either way, how have you tried to do this currently? The cf object is a property of Request so you can get it from that.

If you can show code of how you’re trying to access it currently we can help more. Also remember, it’s only available in the worker, not the client-side JS. So, you would need to either inject it in or return it as part of a call

Thank you for the feedback!

I managed to extract this data, in another application, on its own.

addEventListener("fetch", event => {
  const data =
    event.request.cf !== undefined ?
      event.request.cf :
      { error: "The `cf` object is not available inside the preview." }

  return event.respondWith(handleCf(data))
})


let showData = (data) => {
    
const cf = JSON.parse(data)

    return `
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta http-equiv="x-ua-compatible" content="ie=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Hello!</title>
        <link rel="stylesheet" href="https://unpkg.com/modern-css-reset/dist/reset.min.css" />
        <style>
          body {
            background: #eee;
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            font-family: sans-serif;
          }
          div.container {
            background: #fff;
            border-radius: 1rem;
            padding: 4rem;
          }
        </style>
      </head>
      <body>
        <div class="container">
          <h1>data LP</h1>
          <h3>City: ${cf.city}</h3>
          <h3>Country: ${cf.country}</h3>
          <h3>Continent: ${cf.continent}</h3>
          <h3>latitude: ${cf.latitude}</h3>
          <h3>longitude: ${cf.longitude}</h3>
        </div>
      </body>
    </html>
    `
}



async function handleCf(data) {
const lp= JSON.stringify(data, null, 2)

  try {
    return new Response(showData(lp), {
      headers: { 'content-type': 'text/html' },
    })
    
 } catch (e) {
   let err =JSON.stringify(e);
   console.log('err', err)
 }
}

But my big problem is that I don’t understand how I could extract the data in my React application, without affecting the current functionality.

Yep, so as I mentioned, you would need to either inject it in somehow or offer the info up through like an API call.

In your ReactJS app, you could do a fetch to your Worker and get the info. Something like:
Worker:

const { pathname } = new URL(request.url);

if (pathname === '/api/location') {
  return new Response(JSON.stringify({ city: request.cf.city }), { headers: { 'Content-Type': 'application/json; } });
}

Then in client JS:

componentDidMount() {
  fetch('/api/location')
    .then(res => res.json())
    .then(res => {
      this.setState({ ... })
    })
}

Does that make sense?
You may also be interested in the Workers Discord server, easy way to get help or chat with others: https://workers.community
You may also be interested in Pages: https://pages.dev

Thanks so much for answering @Walshy !
Yes, it makes sense, and I understand what you say needs to be done.

Before your answer, I was trying to use both workers in the React application, so I guess it was a dead end.

Thank you again!

1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.