GeoIP redirect with match URL

Hi,

I am following along with this template: https://developers.cloudflare.com/workers/examples/country-code-redirect

Essentially, I’d like to redirect the naked domain as well as match the URL slug.

Example:

domain.com => en.domain.com
domain.com/some-page => en.domain.com/some-page

How could I accomplish this? Thanks!

You’ll need to use the URL constructor for this:

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


const handleRequest = async (event) => {
	
	const {request} = event
	const url = new URL(request.url)
	const {hostname, pathname, protocol} = url
	const redirectUrl = new URL(pathname, `${protocol}//en.${hostname}${pathname}`)	
	return Response.redirect(redirectUrl.href, 301)
}

Hey thanks for the reply! I plan to map many different country codes to their respective language URL. I see there is already a const rule in the example template. Sorry I am a n00b with JS and workers, so with this template, what would I specifically alter?

/**
 * Returns a redirect determined by the country code
 * @param {Request} request
 */
async function redirect(request) {
  // Use the cf object to obtain the country of the request
  // more on the cf object: https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties
  const country = request.cf.country

  if (country != null && country in countryMap) {
    const url = countryMap[country]
    return Response.redirect(url)
  }
  else {
    return await fetch(request)
  }
}
/**
 * A map of the URLs to redirect to
 * @param {Object} countryMap
 */
const countryMap = {
  US: "https://example.com/us",
  EU: "https://eu.example.com/",
}

async function handleRequest(request) {
  return redirect(request)
}

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

request.cf.country doesn’t work in preview, so you´ll need to deploy to see it working.

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


const handleRequest = async (event) => {
	
	const {request} = event
	const country = request.cf.country
	const url = new URL(request.url)
	const {hostname, pathname, protocol} = url
	
	const countryMap = {
		US: 'en',
		FR: 'fr',
		ES: 'es',
		PA: 'es'
	}
		
	if(country)
	{
		const lang = countryMap.hasOwnProperty(country) ? countryMap[country] : 'en'
		const newHostName = `${lang === 'en' ? '' : lang + '.'}${hostname}`
		
		//en = example.com
		//fr = fr.example.com
		//es = es.example.com
		//pa = es.example.com
		
		if(hostname !== newHostName)
		{
			const redirectUrl = new URL(pathname, `${protocol}//${newHostName}${pathname}`)
			
			return Response.redirect(redirectUrl.href, 301)
		}
		
	}
	
	return await fetch(request)
}

Hi @escribeme I appreciate the help. Sadly, it does not work correctly with the US not being redirected to en.site.com and the other languages get stuck in a redirect loop. Any other suggestions? Also, how could I add a fallback redirect for any unmatched country codes? Btw is there a way to tip you for helping me? haha, I want to show my gratitude. Thank you!

Hey @escribeme just wanted to follow up once more. Is there a reason that only the FR would cause a redirect loop? Also, any way to create a fallback redirect for any unmatched country codes? Thanks!

I am afraid the forum here really is not intended for general JavaScript questions, StackOverflow is better suited for that.