admin管理员组文章数量:1357377
sitemap generation, in dev mode it displays normally. In production when opening the page /sitemap.xml - error 500
server console " 0|front | ⨯ [TypeError: Cannot convert argument to a ByteString because the character at index 131 has a value of 1082 which is greater than 255.] " during assembly in the console "sitemap length 606 "
\src\app\sitemap.ts
import { MetadataRoute } from 'next';
import { getCities } from '@/utils/api/request/cities';
import { getAppConfig } from '@/utils/api/config';
import { getAllPoints } from '@/utils/api/request/points';
import { getAllProducts, filterProductsByMenuIds } from '@/utils/api/request/products';
import { getAllShowcases } from '@/utils/api/request/showcases';
import { createPointsByCityMap } from '@/utils/createPointsByCityMap';
import { BASE_SITEMAP_URL, INCLUDED_LINK_KEYS, LINKS } from '@/app/constants';
function createSitemapEntry(
url: string,
changeFrequency: MetadataRoute.Sitemap[0]['changeFrequency'],
priority: number,
): MetadataRoute.Sitemap[0] {
const encodedUrl = encodeURIComponent(url);
return {
url: encodedUrl,
lastModified: new Date(),
changeFrequency,
priority,
};
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
try {
const [configData, citiesData] = await Promise.all([getAppConfig(), getCities()]);
if (
!configData?.data?.CombinationOfParameters ||
!citiesData?.data ||
!configData.data?.TypeMenu?.Object
) {
throw new Error('Missing required data');
}
const points = await getAllPoints(citiesData);
const cities = citiesData.data;
const menu = configData.data.TypeMenu;
const pointsByCityMap = createPointsByCityMap(cities, points);
const allProducts = await getAllProducts(
cities,
pointsByCityMap,
configData.data.CombinationOfParameters,
);
const sitemapEntries: MetadataRoute.Sitemap = [
createSitemapEntry(BASE_SITEMAP_URL, 'daily', 1),
];
for (const city of cities) {
const cityUrl = `${BASE_SITEMAP_URL}/${city.Url}`;
sitemapEntries.push(createSitemapEntry(cityUrl, 'weekly', 1));
INCLUDED_LINK_KEYS.forEach((key) => {
const link = LINKS[key];
if (typeof link === 'function') {
sitemapEntries.push(
createSitemapEntry(`${BASE_SITEMAP_URL}${link(city.Url)}`, 'weekly', 0.5),
);
} else if (typeof link === 'string') {
sitemapEntries.push(createSitemapEntry(`${BASE_SITEMAP_URL}${link}`, 'weekly', 0.5));
} else if (typeof link === 'object') {
Object.entries(link).forEach(([, childLink]) => {
if (typeof childLink === 'function') {
sitemapEntries.push(
createSitemapEntry(`${BASE_SITEMAP_URL}${childLink(city.Url)}`, 'weekly', 0.5),
);
}
});
}
});
for (const category of menu.Object) {
const categoryUrl = `${BASE_SITEMAP_URL}/${city.Url}/${category.URL}`;
sitemapEntries.push(createSitemapEntry(categoryUrl, 'weekly', 0.8));
const menuIds = category.TypeIDs?.map((typeID) => typeID.ID) || [];
const isShowcase = category.Showcase;
const products = isShowcase
? await getAllShowcases([city], pointsByCityMap, allProducts)
: filterProductsByMenuIds(allProducts, menuIds);
Object.entries(products).forEach(([cityUrl, pointsData]) => {
Object.values(pointsData).forEach((productArrays) => {
productArrays?.flat().forEach((product) => {
sitemapEntries.push(
createSitemapEntry(
`${BASE_SITEMAP_URL}/${cityUrl}/${category.URL}/${product.NameTranslit}`,
'weekly',
0.9,
),
);
});
});
});
}
}
const uniqueSitemapEntries = Array.from(
new Map(sitemapEntries.map((entry) => [entry.url, entry])).values(),
);
console.log('sitemap length', uniqueSitemapEntries?.length);
return uniqueSitemapEntries;
} catch (error) {
console.error('Error generating sitemap:', error);
return [createSitemapEntry(BASE_SITEMAP_URL, 'daily', 1)];
}
}
{
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "npm run clean && cross-env AUTOPREFIXER_GRID=autoplace NODE_EXTRA_CA_CERTS=certs/CAROOT.crt next dev --turbo",
"prebuild": "npm run clear-tags && npm run clean",
"build": "cross-env AUTOPREFIXER_GRID=autoplace NODE_EXTRA_CA_CERTS=certs/CAROOT.crt next build",
"postbuild": "npm run clean-tags",
"start": "cross-env AUTOPREFIXER_GRID=autoplace NODE_EXTRA_CA_CERTS=certs/CAROOT.crt next start",
"lint": "next lint",
"clean": "npx rimraf .next out",
"clear-tags": "node ./src/utils/revalidate/clearTags.mjs",
"clean-tags": "node ./src/utils/revalidate/cleanTags.mjs"
},
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@pbe/react-yandex-maps": "^1.2.5",
"@reduxjs/toolkit": "^2.3.0",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"caniuse-lite": "^1.0.30001699",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"eslint-plugin-compat": "^5.0.0",
"eslint-plugin-prettier": "^5.1.3",
"iron-session": "^8.0.4",
"moment": "^2.30.1",
"moment-timezone": "^0.5.45",
"next": "^15.2.3",
"nextjs-toploader": "^3.7.15",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^9.6.0",
"react": "^19.0.0",
"react-datepicker": "^7.5.0",
"react-dom": "^19.0.0",
"react-google-recaptcha": "^3.1.0",
"react-insta-stories": "^2.7.0",
"react-masonry-css": "^1.0.16",
"react-perfect-scrollbar": "^1.5.8",
"react-phone-input-2": "^2.15.1",
"react-photo-view": "^1.2.6",
"react-range": "^1.10.0",
"react-redux": "^9.1.2",
"react-select": "^5.8.3",
"swiper": "^11.1.4",
"transliteration": "^2.3.5",
"use-media": "^1.5.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react-google-recaptcha": "^2.1.9",
"@types/yandex-maps": "^2.1.36",
"@typescript-eslint/eslint-plugin": "^8.24.0",
"@typescript-eslint/parser": "^8.24.0",
"autoprefixer": "^10.4.19",
"cross-env": "^7.0.3",
"eslint": "^8",
"eslint-config-next": "^15.0.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-css-modules": "^2.12.0",
"prettier": "^3.5.0",
"typescript": "^5.4.5",
"typescript-plugin-css-modules": "^5.1.0"
}
}
node v20.15.1
I expect a list of sitemaps with the ability to revalidate by time or tag or path
I tried to do it through the route, like here .js/discussions/50419
\src\app\api\ppp.xml\route.ts
import { getCities } from '@/utils/api/request/cities';
import { getAppConfig } from '@/utils/api/config';
import { getAllPoints } from '@/utils/api/request/points';
import { getAllProducts, filterProductsByMenuIds } from '@/utils/api/request/products';
import { getAllShowcases } from '@/utils/api/request/showcases';
import { createPointsByCityMap } from '@/utils/createPointsByCityMap';
import { BASE_SITEMAP_URL, LINKS } from '@/app/constants';
const INCLUDED_LINK_KEYS: (keyof typeof LINKS)[] = [
'cashback',
'contacts',
'stock',
'law',
'lawChilds',
'b2b',
'help',
];
function createSitemapEntry(url: string, changefreq: string, priority: number): string {
const encodedUrl = encodeURIComponent(url); // Кодируем URL
return `
<url>
<loc>${encodedUrl}</loc>
<lastmod>${new Date().toISOString()}</lastmod>
<changefreq>${changefreq}</changefreq>
<priority>${priority}</priority>
</url>
`;
}
export async function GET(): Promise<Response> {
try {
const [configData, citiesData] = await Promise.all([getAppConfig(), getCities()]);
if (
!configData?.data?.CombinationOfParameters ||
!citiesData?.data ||
!configData.data?.TypeMenu?.Object
) {
throw new Error('Missing required data');
}
const points = await getAllPoints(citiesData);
const cities = citiesData.data;
const menu = configData.data.TypeMenu;
const pointsByCityMap = createPointsByCityMap(cities, points);
const allProducts = await getAllProducts(
cities,
pointsByCityMap,
configData.data.CombinationOfParameters,
);
let sitemapEntries = createSitemapEntry(BASE_SITEMAP_URL, 'daily', 1.0);
for (const city of cities) {
const cityUrl = `${BASE_SITEMAP_URL}/${city.Url}`;
sitemapEntries += createSitemapEntry(cityUrl, 'weekly', 1.0);
INCLUDED_LINK_KEYS.forEach((key) => {
const link = LINKS[key];
if (typeof link === 'function') {
sitemapEntries += createSitemapEntry(
`${BASE_SITEMAP_URL}${link(city.Url)}`,
'weekly',
0.5,
);
} else if (typeof link === 'string') {
sitemapEntries += createSitemapEntry(`${BASE_SITEMAP_URL}${link}`, 'weekly', 0.5);
} else if (typeof link === 'object') {
Object.entries(link).forEach(([, childLink]) => {
if (typeof childLink === 'function') {
sitemapEntries += createSitemapEntry(
`${BASE_SITEMAP_URL}${childLink(city.Url)}`,
'weekly',
0.5,
);
}
});
}
});
for (const category of menu.Object) {
const categoryUrl = `${cityUrl}/${category.URL}`;
sitemapEntries += createSitemapEntry(categoryUrl, 'weekly', 0.8);
const menuIds = category.TypeIDs?.map((typeID) => typeID.ID) || [];
const isShowcase = category.Showcase;
const products = isShowcase
? await getAllShowcases([city], pointsByCityMap, allProducts)
: filterProductsByMenuIds(allProducts, menuIds);
Object.entries(products).forEach(([cityUrl, pointsData]) => {
Object.values(pointsData).forEach((productArrays) => {
productArrays?.flat().forEach((product) => {
sitemapEntries += createSitemapEntry(
`${BASE_SITEMAP_URL}/${cityUrl}/${category.URL}/${product.NameTranslit}`,
'weekly',
0.9,
);
});
});
});
}
}
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns=".9">
${sitemapEntries}
</urlset>`;
const xmlBuffer = Buffer.from(xml, 'utf-8'); // Преобразуем строку в Buffer с кодировкой UTF-8
const headers = new Headers();
headers.set('Content-Type', 'application/xml; charset=UTF-8'); // Устанавливаем кодировку в заголовках
return new Response(xmlBuffer, { headers });
} catch (error) {
console.error('Error generating sitemap:', error);
return new Response('<?xml version="1.0" encoding="UTF-8"?><urlset></urlset>', {
headers: { 'Content-Type': 'application/xml; charset=UTF-8' },
});
}
}
works, but if I add cache - export const revalidate = 4000; then the same error "[TypeError: Cannot convert argument to a ByteString because the character at index 131 has a value of 1082 which is greater than 255.] "
本文标签:
版权声明:本文标题:nextjs 15 - next js 15, app, sitemap - Cannot convert argument to a ByteString - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744080116a2587475.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论