Dynamic sitemap times out sometimes (next-sitemap) - next.js

I implemented a dynamic server side sitemap using next-sitemap package.
And it works smoothly on my local, but when i visit the production sitemap url (https://www.my-url.com/sitemap-dynamic.xml ) it takes too long to load sometimes.
The issue is that the proxy cuts of the request with a 499 response or even 500, after its timeout (30/60 seconds+), resulting in search engines not being able to read the sitemap.
FYI what I did is the same as it's explained in the demo with my customization :
// pages/server-sitemap-index.xml/index.tsx
import { getServerSideSitemapIndex } from 'next-sitemap'
import { GetServerSideProps } from 'next'
export const getServerSideProps: GetServerSideProps = async (ctx) => {
// Method to source urls from cms
// const urls = await fetch('https//example.com/api')
return getServerSideSitemapIndex(ctx, [
'https://example.com/path-1.xml',
'https://example.com/path-2.xml',
])
}
// Default export to prevent next.js errors
export default function SitemapIndex() {}
For instance check if we can prewarm the sitemap and refresh it at interval x (hourly/daily ?)
Did someone face or hear about this problem before ? please a hint , and thanks in advance

Related

Vercel circular redirects when using Firebase authentication

I do have a super weird error coming up only when deploying the code to Vercel. It doesn't happen locally which makes it quite annoying to begin with.
I do have a staging and a production instance for my code. I want to protect the staging with a password which is not difficult since I implemented the authentication via Firebase. The only tricky part is that I don't use Firebase to keep track of the user but my server (basically setting a cookie). I should mention that I am using Sveltekit to put it all together.
In sveltekit you can use hooks, which can be seen as middlewares, to redirect a user to the sign-in page if the env variable for the environment is set to dev.
Another hook redirects a logged-in user, so if you are already logged in and try to go to auth/sign-in or auth/sign-up you'll get redirected to the home page.
Now the weird happens: I go on the deployed version of the site, and I get immediately redirected to the sign-in page, which is correct. I try to navigate to all the pages of the website, the redirect still works fine. I log in and upon success, I should be redirected to the homepage, which I do BUT the home page redirects me to the sign-in page as if I wasn't logged in and again the sign-in page redirects me to the home page as if I was, thus creating a loop.
I honestly don't know why this happens since it perfectly works locally, so my thoughts go to Vercel. I would exclude Firebase since I remembered to put the custom domain as an allowed domain in the settings.
To give a bitmore context, I structured the hooks responsible for the redirect in this way:
export const authSessionHandler: Handle = async ({ event, resolve }) => {
const cookie = event.locals.cookie;
const idToken = await getIdTokenFromSessionCookie(getCookieValue(cookie, 'session'));
const user = idToken
? {
uid: idToken?.sub,
email: idToken?.email
}
: null;
event.locals.idToken = idToken;
event.locals.user = user;
return resolve(event);
};
export const redirectLoggedInUserHandler: Handle = async ({ event, resolve }) => {
const { user } = event.locals;
const next = event.url.searchParams.get('next') || '/';
if (
user &&
(event.url.pathname.startsWith('/auth/sign-in') ||
event.url.pathname.startsWith('/auth/sign-up'))
) {
return new Response('Redirect', {
status: http_302.status,
headers: {
location: `${next}`
}
});
}
return resolve(event);
};
export const redirectToSignInForDevEnvironmentHandler: Handle = async ({ event, resolve }) => {
const { user } = event.locals;
const allowedEndpoints = ['/auth/sign-in', '/auth/session'];
if (!user && env === 'dev' && !allowedEndpoints.includes(event.url.pathname)) {
return new Response('Redirect', {
status: http_302.status,
headers: {
location: '/auth/sign-in'
}
});
}
return resolve(event);
};
The handlers are in that order, so the first one populates the user and the rest can check the rest.
In the code I am getting the user from event.locals which kind of decides the entire logic (as it should) and to me it's quite interesting and telling the fact that the sign-in page redirects me to home which mean the user is defined, but the home page redirects back as if the user was not defined. This made me think it is not a problem with the code but probably the provider(s) Vercel or Firebase.
It would be very helpful to know your thoughts about it.

Nuxt middleware not triggered upon initial render

The following code is meant to check the role of the user.
The middleware runs everytime the site is reloaded are a new route is taken.
// Some nuxt middleware
import * as firebase from 'firebase/app'
import 'firebase/auth'
export default function ({ app, store, route, redirect }) {
app.router.beforeEach((to, from, next) => {
// For some reason, this does not load every time.
firebase.auth().onAuthStateChanged((userAuth) => {
if (userAuth) {
console.log(userAuth)
firebase
.auth()
.currentUser.getIdTokenResult()
.then(function ({ claims }) {
// some auth stuff
})
})
}
For some reason, if the site is reloaded this user auth function always returns null. This leads to that the rest of the functions fail due to the unknown user data / user roles.
firebase.auth().onAuthStateChanged((userAuth) => {...})
So my question is, why does the upper function return null when the site is reloaded?
ps. Everything works normal if a new route is taken, it only fails when site is reloaded.
beforeEach is a guard triggered when you navigate from a page to another page thanks to vue router, aka using <nuxt-link> or $router.push.
On the initial page load, there is no navigation because you're rendering the content generated by the server, not the client directly.
Definition of a middleware from Nuxt's documentation
Middleware lets you define custom functions that can be run before rendering either a page or a group of pages (layout).
Notice, before rendering. This means that a middleware will be run as your beforeEach and on initial render.
Hence, you can totally strip the router guard part and simply let the middleware as this
export default function ({ app, store, route, redirect }) {
firebase.auth().onAuthStateChanged((userAuth) => {
...

How to verify the request is coming from my application clientside?

I have an app where users can create posts. There is no login or user account needed! They submit content with a form as post request. The post request refers to my api endpoint. I also have some other api points which are fetching data.
My goal is to protect the api endpoints completely except some specific sites who are allowed to request the api ( I want to accomplish this by having domain name and a secure string in my database which will be asked for if its valid or not if you call the api). This seems good for me. But I also need to make sure that my own application is still able to call the api endpoints. And there is my big problem. I have no idea how to implement this and I didn't find anything good.
So the api endpoints should only be accessible for:
Next.js Application itself if somebody does the posting for example
some other selected domains which are getting credentials which are saved in my database.
Hopefully somebody has an idea.
I thought to maybe accomplish it by using env vars, read them in getinitalprops and reuse it in my post request (on the client side it can't be read) and on my api endpoint its readable again. Sadly it doesn't work as expected so I hope you have a smart idea/code example how to get this working without using any account/login strategy because in my case its not needed.
index.js
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
export default function Home(props) {
async function post() {
console.log(process.env.MYSECRET)
const response = await fetch('/api/hello', {
method: 'POST',
body: JSON.stringify(process.env.MYSECRET),
})
if (!response.ok) {
console.log(response.statusText)
}
console.log(JSON.stringify(response))
return await response.json().then(s => {
console.log(s)
})
}
return (
<div className={styles.container}>
<button onClick={post}>Press me</button>
</div>
)
}
export async function getStaticProps(context) {
const myvar = process.env.MYSECRET
return {
props: { myvar },
}
}
api
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default function handler(req, res) {
const mysecret = req.body
res.status(200).json({ name: mysecret })
}
From what I understand, you want to create an API without user authentication and protect it from requests that are not coming from your client application.
First of all, I prefer to warn you, unless you only authorize requests coming from certain IPs (be careful with IP Spoofing methods which could bypass this protection), this will not be possible. If you set up an API key that is shared by all clients, reverse engineering or sniffing HTTP requests will retrieve that key and impersonate your application.
To my knowledge, there is no way to counter this apart from setting up a user authentication system.

getStaticPaths and getStaticProps with domain flavouring

I have a question related to the static generation of Next.js:
I'm creating whitelabel websites for my customers; it means that I'm reading the domain where the request is coming from to load a config file and some specific CSS files. That's working fine and looks like this:
export const readConfig = async ({req}) => {
const configs = await import('../configs.json')
const domain = req ? req.headers['host'].split(':')[0] : window.location.hostname
const config = configs[domain]
return {domain, config}
}
Page.getInitialProps = readConfig
However, I'm using getInitialProps for that and my understanding is that because I rely on req, this code will be loaded for every page.
Now, let's say that I want to have a static generation of some pages, how should I proceed? Can I avoid having count_different_domains * count_different_items combinations? Is that somehow possible to cache the result of some queries and revalidate it later (but not as entire Page)?

Why is the css no longer loaded if I add a key to the url?

My app is in Koa JS.
The code below generates a website with full css (http://localhost:3000/product):
module.exports = (router, productsLoader) => {
router.get("/product", async ctx => {
const product = await productsLoader.single(ctx.params.slug)
ctx.state.model = {
title: 'Hey there,',
products: product
}
await ctx.render('product');
})
}
However if I add a key (:slug) to the url, the website can show the bare content but not any css features (http://localhost:3000/product/abc):
module.exports = (router, productsLoader) => {
router.get("/product/:slug", async ctx => {
const product = await productsLoader.single(ctx.params.slug)
if (product) {
ctx.state.model = {
title: product.name,
product: product
}
await ctx.render('product')
}
})
}
My intuition tells me it is something to do with async and await, but I couldn't find out exactly what went wrong.
edit:
In the website below, it said "So CSS doesn't get sent along with the pages in a dynamic site like this. The HTML gets sent to the client, and then the client requests the files from the server. So what I did was I added a router to the CSS in my app.js" & "But on a dynamic site, when a request is made, and a response is sent, the response is sent to the '/', and NOT to the subfolder that's on the server side (at least by default). There is no subfolder on the client's side. Responses are simply just sent to the '/' by default. So make sure that the HTML is referencing the client side's files, and not the server side's files!"
But if I have lots of css files to reference to, then that means I have to manually reference to those files again? that sounds quite counter intuitive as Koa Js is supposed to be more convenient!
https://teamtreehouse.com/community/cant-get-the-css-to-load-in-the-nodejs-server

Resources