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 шт):
В
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;
});
}