Next.js 14.2.1 + Yandex.Map Api ошибка No 'Access-Control-Allow-Origin' header is present on the requested resource

Не могу вызвать карту через Script на localhost. Выползает ошибка No 'Access-Control-Allow-Origin' header is present on the requested resource. На Next.js 14.0.2 все работает

layout.js

import { YMapLoader } from "../components/YMapLoader/YMapLoader";

export const metadata = {
    title: "IP-ADDRESS-TRACKER",
    description: "Frontend mentor challenge",
};

export default function RootLayout({ children }) {
    return (
        <html lang="en">
            <body className="min-h-screen bg-dark-gray">
                {children}
                <YMapLoader />
            </body>
        </html>
    );
}

page.js

"use client";
import dynamic from "next/dynamic";

const Map = dynamic(() => import("@/app/components/Map/Map"), { ssr: false });

export default function About() {
    return (
        <>
            <main className="relative">
                <Map />
            </main>
        </>
    );
}


YMapLoader.js

import Script from 'next/script';

const MAP_API_KEY = process.env.MAP_API_KEY;

export const YMapLoader = () => {
  return (
    <>
      <Script
        src={`https://api-maps.yandex.ru/3.0/?apikey="ключ"&lang=en_US`}
        type="module"
        strategy="beforeInteractive"
      />
    </>
  );
};

map.js

'use client';
import Image from 'next/image';
import React from 'react';
import ReactDOM from 'react-dom';

const ymaps3Reactify = await ymaps3.import('@yandex/ymaps3-reactify');
const reactify = ymaps3Reactify.reactify.bindTo(React, ReactDOM);
const { YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapControls, YMapMarker } =
  reactify.module(ymaps3);

const { YMapZoomControl } = reactify.module(await ymaps3.import('@yandex/[email protected]'));

const Map = () => {
  const location = { center: [55.751574, 37.573856], zoom: 13 };

  return (
    <YMap location={location} className="min-h-[calc(100vh-300px)] md:min-h-[calc(100vh-280px)]">
      <YMapControls position="left">
        <YMapZoomControl />
      </YMapControls>

      <YMapDefaultSchemeLayer />
      <YMapDefaultFeaturesLayer />

      <YMapMarker coordinates={location.center} zIndex={1}>
        <div className="relative h-[56px] w-[46px]">
          <Image src="/icon-location.svg" alt="location" fill />
        </div>
      </YMapMarker>
    </YMap>
  );
};

export default Map;

Ответы (1 шт):

Автор решения: HeyLalaley

В

YMapLoader.js

убрать type="module", который вызывает проверки cors. Либо использовать обратный прокси сервер для запросов, который, в отличии от браузера, не будет ожидать обратных cors заголовков от конечного сервера. Если по простому, можно через встроенные роуты в nextjs:

Создайте файл route.js в api/v1/maps-proxy/route.js

export async function GET(req) {
  try {
    const { searchParams } = new URL(req.url);
    const apiKey = process.env.MAP_API_KEY;

    // Сбор параметров для Yandex API
    const yandexApiUrl = "https://api-maps.yandex.ru/3.0/";
    const requestParams = {
      apikey: apiKey,
      lang: "ru_RU",
      ...Object.fromEntries(searchParams),
    };

    // Сохранение заголовков, переданных в запросе
    const incomingHeaders = Object.fromEntries(req.headers.entries());
    console.log("Incoming request headers:", incomingHeaders);

    // Логируем параметры запроса
    console.log("Proxying request to Yandex API:", {
      url: yandexApiUrl,
      params: requestParams,
    });

    // Отправляем запрос на конечный сервер
    const response = await axios.get(yandexApiUrl, {
      params: requestParams,
      responseType: "stream",
      incomingHeaders,
    });

    // Логируем заголовки ответа от Yandex API
    const responseHeaders = response.headers;
    console.log("Response headers from Yandex API:", responseHeaders);

    // Возвращаем данные ответа вместе с заголовками
    const proxyResponse = new Response(response.data, {
      headers: new Headers(responseHeaders),
    });

    return proxyResponse;
  } catch (error) {
    console.error("Error proxying the request:", error.message);
    return NextResponse.json(
      { error: "Failed to proxy request.", details: error.message },
      { status: 500 }
    );
  }
}

Теперь в YMapLoader.js вызывайте src="/api/v1/maps-proxy"

Но лучше использовать отдельный прокси, тот же ngnix.

Ещё можно добавить перед const ymaps3Reactify = await ymaps3.import('@yandex/ymaps3-reactify'); следующий код, который гарантирует, что ymaps3 будет загружен:

if (!window.ymaps3) {
  console.log('Yandex Maps не загружены. Загружаем скрипт...');

  // Создаём элемент script для загрузки Yandex Maps API
  const script = document.createElement('script');
  script.src = 'https://api-maps.yandex.ru/3.0/?apikey={yourToken}&lang=ru_RU';
  script.async = true;
  document.head.appendChild(script);

  // Ожидаем, пока скрипт загрузится
  await new Promise((resolve, reject) => {
    script.onload = resolve;
    script.onerror = reject;
  });
}
→ Ссылка