Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catching 404 errors on server side #7101

Closed
L1xx3r opened this issue Sep 30, 2022 · 14 comments
Closed

Catching 404 errors on server side #7101

L1xx3r opened this issue Sep 30, 2022 · 14 comments

Comments

@L1xx3r
Copy link

L1xx3r commented Sep 30, 2022

Describe the problem

Some code a while go worked perfectly:

__error.js

import customFetch from '$lib/customFetch'
import { setCookie } from '$lib/helpers'

export async function load ({ url, error, status }) {
  if (status === 404 && !(url.pathname.substring(1)).includes('/')) {
    return await customFetch
      .service('api/redirects')
      .get(url.path.substring(1))
      .then(redirect => {
        if (redirect.cookie) {
          setCookie(redirect.cookieName, redirect.cookieValue)
        }
        return {
          status: redirect.status,
          redirect: redirect.location
        }
      })
      .catch(() => {
        return {
          props: {
            status: status,
            error: error.message
          }
        }
      })
  } else {
    return {
      props: {
        status: status,
        error: error.message
      }
    }
  }
}

but now none of this will work, and I cannot make it work in any way other than in a way that loads the whole site.

This is used in 2 ways.

  1. If you change the structure of your site, for SEO reasons, you want a 301 redirect.

  2. I also use it for short links for affiliate forwarding using a 307 redirect.

The load function also doesn't have error or status so I cannot do it in +layout.server.js

Describe the proposed solution

Allow +error.js or +error.server.js files, or have the error in +layout.server.js??

Alternatives considered

No response

Importance

would make my life easier

Additional Information

No response

@dummdidumm
Copy link
Member

Duplicate of #6106

@dummdidumm dummdidumm marked this as a duplicate of #6106 Oct 10, 2022
@dummdidumm dummdidumm closed this as not planned Won't fix, can't repro, duplicate, stale Oct 10, 2022
@L1xx3r
Copy link
Author

L1xx3r commented Oct 10, 2022

@dummdidumm this isn't a duplicate of #6106 at least not in the solution.

I am looking for a way to catch 404s that are not in the routes, having my function in the +layout.server.js will not know yet it is a 404 error, unless i am mistaken.

@dummdidumm
Copy link
Member

No, you won't find out if it's a 404 or not because the layout doesn't run until it's determined which route to go to (or none, in the case of 404). Adding something to layout which says "you're on a 404 route" isn't wanted in the current design.

What you can do for this specific problem is to create a catch-all route, from which you redirect:

// src/routes/[...notFound]/+page.js
export function load() {
  // you end up here when no other route was matched, i.e. the 404 case
  throw redirect(301, 'somewhere/else');
}

@L1xx3r
Copy link
Author

L1xx3r commented Oct 10, 2022

I thought +page.js ran after the site was loaded?

I am unclear the difference between +page.server.js and +page.js for where to add the load and catch the 404s

@dummdidumm
Copy link
Member

you can place it in +page.js or +page.server.js, it doesn't make a difference. Both are run before the Svelte component/page is rendered.

@L1xx3r
Copy link
Author

L1xx3r commented Oct 10, 2022

@dummdidumm Ummm... throwing redirect is not working.

However vite console prints this:

Redirect { status: 307, location: 'https://example.com' }

The site doesn't redirect, page still loads as a 404.

I tried both +page.js and +page.server.js

Even tried a local existing path:

Redirect { status: 307, location: '/administrate' } was printed and no redirect...

This is how i am throwing: throw redirect(obj[0].status, obj[0].location) and based on the printing, the variables are loading.

@L1xx3r
Copy link
Author

L1xx3r commented Oct 11, 2022

@dummdidumm ?? Hello? Is this a new issue ? I don't want to create another unless I need to.

@dummdidumm
Copy link
Member

Just tried it out, works for me.

// [...notfound]/+page.js
import { redirect } from '@sveltejs/kit';

export function load() {
  throw redirect(307, '/docs'); // or whereever you want to redirect
}

@L1xx3r
Copy link
Author

L1xx3r commented Oct 11, 2022

Strange, it doens't work for me.

Do you see any reason it will not work with this:

import env from '$lib/env'
import { error, redirect } from '@sveltejs/kit'
import got from 'got'

export async function load ({ url }) {
  let e404 = false

  const sitePage = await got(`${env.api}/site-pages/?pathname=${url.pathname}`)
    .then(response => {
      let obj = JSON.parse(response.body)
      obj = obj.data || obj
      if (obj[0]) {
        return obj[0]
      } else {
        e404 = true
        return null
      }
    })
    .catch((e) => {
      console.error(e)
      e404 = true
    })

  console.log('sitePage', sitePage)

  if (e404) {
    await got(`${env.api}/redirects/?linkName=${url.pathname}`)
      .then(response => {
        let obj = JSON.parse(response.body)
        obj = obj.data || obj
        if (obj[0]) {
          throw redirect(obj[0].status, obj[0].location)
        }
      })
      .catch((e) => {
        console.error(e)
        e404 = true
      })
  }

  if (e404) throw error(404, 'not-found')

  return {
    sitePage
  }
}

Considering all the data requests are working as expected (I have confirmed this with console logs)?

@L1xx3r
Copy link
Author

L1xx3r commented Oct 11, 2022

HAhaha wait a sec, I am catching the throw... lol My bad!

@dummdidumm
Copy link
Member

dummdidumm commented Oct 11, 2022

I can't tell from reading the code without context what is going on. Have you tried to throw out everything in that load function and just try to redirect to some url?

Also that throw error(404) looks suspicious. Are we talking past each other? My proposed solution is to create a [...rest]/+page.js which will catch all routes your other routes don't match. I'm not sure what you are trying to do in that load function exactly

@L1xx3r
Copy link
Author

L1xx3r commented Oct 11, 2022

@dummdidumm the following works perfectly. Thanks for your help:

import env from '$lib/env'
import { error, redirect } from '@sveltejs/kit'
import got from 'got'
import _ from 'lodash'

export async function load ({ url }) {
  let e404 = false
  let redirectObj = {}

  const sitePage = await got(`${env.api}/site-pages/?pathname=${encodeURI(url.pathname)}`)
    .then(response => {
      let obj = JSON.parse(response.body)
      obj = obj.data || obj
      if (obj[0]) {
        return obj[0]
      } else {
        e404 = true
        return null
      }
    })
    .catch((e) => {
      console.error(e)
      e404 = true
    })

  if (e404) {
    redirectObj = await got(`${env.api}/redirects/?pathname=${url.pathname}`)
      .then(response => {
        let obj = JSON.parse(response.body)
        obj = obj.data || obj
        if (obj[0]) {
          return obj[0]
        }
      })
      .catch((e) => {
        console.error(e)
        e404 = true
      })
  }

  if (!_.isEmpty(redirectObj)) throw redirect(redirectObj.status, redirectObj.location)
  if (e404) throw error(404, 'not-found')

  return {
    sitePage
  }
}

@nohea
Copy link

nohea commented Oct 13, 2022

HAhaha wait a sec, I am catching the throw... lol My bad!

caught me too.

I think this is a 'not good coding style' to have throw redirect() for normal flow control. A redirect may or may not be an error condition, so it should not require throw. Now we have to work around throw redirect() in *.server.ts try blocks.

@L1xx3r
Copy link
Author

L1xx3r commented Oct 13, 2022

@nohea I agree completely. Throwing it like an error when it is the wanted action is strange and confusing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants