nextjs 15 - next js 15, app, sitemap - Cannot convert argument to a ByteString - Stack Overflow

sitemap generation, in dev mode it displays normally. In production when opening the page sitemap.xml

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.] "

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744080116a4555129.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信