4 min
9 września 2024
Łatwy sposób obsługi stron 404 ze Storyblok za pomocą Nuxtjs
Podczas tworzenia strony internetowej kluczowe znaczenie ma zapewnienie płynnego doświadczenia użytkownika. Zdarzają się jednak sytuacje, w których użytkownik może przejść do strony, która nie istnieje, co skutkuje błędem „404 Not Found”. Chociaż jest to powszechny problem, sposób obsługi stron błędu 404 może znacząco wpłynąć na wrażenia użytkownika. W tym wpisie na blogu zbadamy, jak obsługiwać strony błędów 404 w projekcie Nuxt.js zintegrowanym ze Storyblok jako headless CMS.
Posłuchaj artykułu w wersji audio.
Dlaczego warto dostosowywać strony błędów 404?
Ogólna strona błędu 404 może być ślepą uliczką dla użytkowników, prowadząc do frustracji i potencjalnej utraty zaangażowania. Dostosowując tę stronę, można
Zachować spójność marki.
Zapewnić przydatne informacje i opcje nawigacji.
Zaangażować użytkowników i poprowadzić ich z powrotem do odpowiednich treści.
Problem
Storyblok nie ma jasnych wytycznych w dokumentacji dotyczących obsługi stron 404. Co więcej, nie ma dedykowanego punktu końcowego w Content Delivery API V2. Jedynym sposobem, aby dowiedzieć się, czy historia istnieje, jest próba jej pobrania.
Opcja A (obsługa błędów bezpośrednio na stronie)
Wyzwól context.error wszędzie tam, gdzie pobieramy dane dla stron, jeśli złapiemy błąd. Będzie to wyglądać mniej więcej tak
export default defineComponent({
setup(_props, context: any) {
const storyblokApi = useStoryblokApi();
const { fetch } = useFetch(async () => {
try {
const { data } = await storyblokApi.get(`cdn/stories/test-story`, {
version: 'draft',
});
const results = (data as any)?.story ?? null;
// save story
} catch (error) {
console.log('error', error);
if (typeof error === 'string') {
const parsedError = JSON.parse(error as string);
context.error({ statusCode: parsedError.status ?? 500 });
} else {
context.error({ statusCode: 500 });
}
}
});
}
})
Problem z tym rozwiązaniem polega na tym, że musimy kopiować i wklejać ten kod w wielu miejscach w naszej bazie kodu. Innym powodem, dla którego nie warto korzystać z tej opcji jest to, że widzimy układ strony przez chwilę, zanim zostaniemy przekierowani na stronę 404. Aby rozwiązać ten problem, możemy użyć oprogramowania pośredniczącego.
Opcja B (middleware + pinia)
Utwórz oprogramowanie pośredniczące do obsługi pobierania storybloków i zapisywania wyników w globalnym magazynie. Będziemy używać pinia store.
stores/storyblok.ts
import { defineStore } from 'pinia';
interface StoryblokState {
currentStory: any;
}
export const useStoryblokStore = defineStore('storyblok', {
state: (): StoryblokState => ({
currentStory: {},
}),
});
middleware/story-url-resolver.ts
import { Middleware } from '@nuxt/types';
import { useStoryblokStore } from '~/stores/storyblok';
import { storeToRefs } from 'pinia';
const urlResolverMiddleware : Middleware = async (context) => {
const storyblokApi = useStoryblokApi();
const storyblokStore = useStoryblokStore();
const { path } = context.route;
try {
const { data } = await storyblokApi.get(`cdn/stories/${path}`, {
version: 'draft',
});
const results = (data as any)?.story ?? null;
storyblokStore.$patch((state) => {
state.currentStory = results;
});
} catch (error) {
console.log('error', error);
if (typeof error === 'string') {
const parsedError = JSON.parse(error as string);
context.error({ statusCode: parsedError.status ?? 500 });
} else {
context.error({ statusCode: 500 });
}
}
};
To rozwiązanie wydaje się działać, ale teraz napotykamy znany błąd w Nuxtjs v2, o którym mowa tutaj.
Ogólnie rzecz biorąc, problem polegał na tym, że w momencie równoległego otwarcia strony (na dowolnym urządzeniu) kontekst aplikacji był współdzielony, a strona B miała w SSR dane strony A, co skutkowało błędem w renderowaniu zawartości strony.
Opcja C (middleware + kontekst)
Teraz nie będziemy używać pinia store, zamiast tego zapiszemy historię bezpośrednio w kontekście oprogramowania pośredniczącego.
import { Middleware } from '@nuxt/types';
const urlResolverMiddleware : Middleware = async (context) => {
const storyblokApi = useStoryblokApi();
const { path } = context.route;
try {
const { data } = await storyblokApi.get(`cdn/stories/${path}`, {
version: 'draft',
});
const results = (data as any)?.story ?? null;
// crucial change
context.app.currentStory = results;
} catch (error) {
console.log('error', error);
if (typeof error === 'string') {
const parsedError = JSON.parse(error as string);
context.error({ statusCode: parsedError.status ?? 500 });
} else {
context.error({ statusCode: 500 });
}
}
};
Musimy dokonać drobnych zmian w naszych komponentach stron, aby używać asyncData w celu pobierania danych z kontekstu na kliencie i na serwerze
<script lang="ts">
export default {
layout: 'basic',
async asyncData(context) {
return { currentStory: context.app.currentStory }
},
middleware: [
'story-url-resolver',
],
};
</script>