提问人:French At Home 提问时间:10/29/2023 最后编辑:French At Home 更新时间:10/29/2023 访问量:45
从 NodeJS 服务器获取 Google Maps API 密钥的 CORS 问题
CORS Issue Fetching Google Maps API Key from NodeJS Server
问:
我开发了一个托管在 GitHub Pages 上的 JavaScript Webpack 前端应用程序,它与部署在 Heroku 上的 NodeJS 服务器进行通信。
为了增强安全性,我将 Google Maps API 密钥从前端代码中移出,并将其存储在 Heroku 环境变量中。
密钥由前端通过 NodeJS 服务器上的 API 端点检索。
但是,我遇到了阻止前端访问 API 密钥的 CORS 问题。
- 我将我的 Google Maps API 密钥存储在 Heroku 上的环境变量中:
heroku config:set GOOGLE_MAPS_API_KEY=my_api_key
- 后端代码(NodeJS Express):
app.get('/api/google-maps-api-key', (req, res) => {
const googleMapsApiKey = process.env.GOOGLE_MAPS_API_KEY;
if (!googleMapsApiKey) {
res
.status(500)
.json({ error: 'Google Maps API key not found on the server.' });
} else {
res.json({ googleMapsApiKey });
}
});
- 前端代码
我的地点.js:
fetch('https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/api/google-maps-api-key')
.then(response => response.json())
.then(data => {
const googleMapsApiKey = data.googleMapsApiKey;
document.querySelector('script').src = `https://maps.googleapis.com/maps/api/js?key=${googleMapsApiKey}&callback=Function.prototype`;
})
.catch(error => {
console.error('Failed to fetch Google Maps API key:', error);
});
SharePlace.js:
fetch('https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/api/google-maps-api-key')
.then(response => response.json())
.then(data => {
const googleMapsApiKey = data.googleMapsApiKey;
document.querySelector('script').src = `https://maps.googleapis.com/maps/api/js?key=${googleMapsApiKey}&callback=Function.prototype`;
})
.catch(error => {
console.error('Failed to fetch Google Maps API key:', error);
});
位置.js:
export async function getAddressFromCoords(coords) {
try {
const response = await fetch(
`https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/api/google-maps-api-key`
);
if (!response.ok) {
throw an Error('Failed to fetch Google Maps API key from the server.');
}
const data = await response.json();
const googleMapsApiKey = data.googleMapsApiKey;
const geocodeResponse = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${coords.lat},${coords.lng}&key=${googleMapsApiKey}`
);
if (!geocodeResponse.ok) {
throw new Error('Failed to fetch address. Please try again!');
}
const geocodeData = await geocodeResponse.json();
if (geocodeData.error_message) {
throw new Error(geocodeData.error_message);
}
const address = geocodeData.results[0].formatted_address;
return address;
} catch (error) {
throw new Error('Failed to fetch address. Please try again!');
}
}
export async function getCoordsFromAddress(address) {
try {
const response = await fetch(
`https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/api/google-maps-api-key`
);
if (!response.ok) {
throw new Error('Failed to fetch Google Maps API key from the server.');
}
const data = await response.json();
const googleMapsApiKey = data.googleMapsApiKey;
const urlAddress = encodeURI(address);
const geocodeResponse = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?address=${urlAddress}&key=${googleMapsApiKey}`
);
if (!geocodeResponse.ok) {
throw new Error('Failed to fetch coordinates. Please try again!');
}
const geocodeData = await geocodeResponse.json();
if (geocodeData.error_message) {
throw new Error(geocodeData.error_message);
}
const coordinates = geocodeData.results[0].geometry.location;
return coordinates;
} catch (error) {
throw new Error('Failed to fetch coordinates. Please try again!');
}
}
- 错误消息:
CORS 策略已阻止从源“https://sofiane-abou-abderrahim.github.io”在“https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/api/google-maps-api-key”处提取:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明响应满足您的需求,请将请求的模式设置为“no-cors”,以在禁用 CORS 的情况下获取资源。
分享位置.js:10 GET https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/api/google-maps-api-key net::ERR_FAILED 200 (OK)
SharePlace.js:15 无法获取 Google Maps API 密钥:TypeError:无法在 eval 处获取 (SharePlace.js:10:1)
- 我的问题:
如何解决阻止我在 GitHub Pages 上的前端应用程序向 Heroku 上的 NodeJS 服务器发出请求以获取 Google Maps API 密钥的 CORS 问题?
我应该对服务器或前端代码进行哪些更改,以确保在不影响安全性的情况下成功检索 API 密钥?
编辑:
根据评论的要求,这是我对某些文件的完整代码,以便我提供有关我的问题和我尝试过的内容的更多详细信息。
app.js
(服务器端):
const express = require('express');
const bodyParser = require('body-parser');
const locationRoutes = require('./routes/location');
const app = express();
app.use(bodyParser.json());
const allowedOrigin =
process.env.ALLOWED_ORIGIN || 'https://sofiane-abou-abderrahim.github.io';
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', allowedOrigin);
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
next();
});
app.use(locationRoutes);
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
SharePlace.js
(前端):
import { Modal } from './UI/Modal';
import { Map } from './UI/Map';
import { getCoordsFromAddress, getAddressFromCoords } from './Utility/Location';
import { key } from '../key';
document.querySelector(
'script'
).src = `https://maps.googleapis.com/maps/api/js?key=${key}&callback=Function.prototype`;
class PlaceFinder {
constructor() {
const addressForm = document.querySelector('form');
const locateUserBtn = document.getElementById('locate-btn');
this.shareBtn = document.getElementById('share-btn');
locateUserBtn.addEventListener('click', this.locateUserHandler.bind(this));
this.shareBtn.addEventListener('click', this.sharePlaceHandler);
addressForm.addEventListener('submit', this.findAddressHandler.bind(this));
}
sharePlaceHandler() {
const sharedLinkInputElement = document.getElementById('share-link');
if (!navigator.clipboard) {
sharedLinkInputElement.select();
return;
}
navigator.clipboard
.writeText(sharedLinkInputElement.value)
.then(() => {
alert('Copied into clipboard!');
})
.catch(err => {
console.log(err);
sharedLinkInputElement.select();
});
}
selectPlace(coordinates, address) {
if (this.map) {
this.map.render(coordinates);
} else {
this.map = new Map(coordinates);
}
fetch(
'https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/add-location',
{
method: 'POST',
body: JSON.stringify({
address: address,
lat: coordinates.lat,
lng: coordinates.lng
}),
headers: {
'Content-Type': 'application/json'
}
}
)
.then(response => {
return response.json();
})
.then(data => {
const locationId = data.locId;
this.shareBtn.disabled = false;
const sharedLinkInputElement = document.getElementById('share-link');
const pathnameParts = window.location.pathname.split('/');
const repositoryName = pathnameParts[1]; // Get the first part of the pathname (GitHub username or organization)
sharedLinkInputElement.value = `${location.origin}/${repositoryName}/my-place?location=${locationId}`;
});
}
locateUserHandler() {
if (!navigator.geolocation) {
alert(
'Location feature is not available in your browser - please use a more modern browser or manually enter an address.'
);
return;
}
const modal = new Modal(
'loading-modal-content',
'Loading location - please wait!'
);
modal.show();
navigator.geolocation.getCurrentPosition(
async successResult => {
const coordinates = {
lat: successResult.coords.latitude + Math.random() * 50,
lng: successResult.coords.longitude + Math.random() * 50
};
const address = await getAddressFromCoords(coordinates);
modal.hide();
this.selectPlace(coordinates, address);
},
error => {
modal.hide();
alert(
'Could not locate you unfortunately. Please enter an address manually!'
);
}
);
}
async findAddressHandler(event) {
event.preventDefault();
const address = event.target.querySelector('input').value;
if (!address || address.trim().length === 0) {
alert('Invalid address entered - please try again!');
return;
}
const modal = new Modal(
'loading-modal-content',
'Loading location - please wait!'
);
modal.show();
try {
const coordinates = await getCoordsFromAddress(address);
this.selectPlace(coordinates, address);
} catch (err) {
alert(err.message);
}
modal.hide();
}
}
const placeFinder = new PlaceFinder();
MyPlace.js(前端):
import { Map } from './UI/Map';
import { key } from '../key';
document.querySelector(
'script'
).src = `https://maps.googleapis.com/maps/api/js?key=${key}&callback=Function.prototype`;
class LoadedPlace {
constructor(coordinates, address) {
new Map(coordinates);
const headerTitleEl = document.querySelector('header h1');
headerTitleEl.textContent = address;
}
}
const url = new URL(location.href);
const queryParams = url.searchParams;
// const coords = {
// lat: parseFloat(queryParams.get('lat')),
// lng: +queryParams.get('lng')
// };
// const address = queryParams.get('address');
const locId = queryParams.get('location');
fetch(
'https://nodejs-share-my-place-06b87a0b20ab.herokuapp.com/location/' + locId
)
.then(response => {
if (response.status === 404) {
throw new Error('Could not find location!');
}
if (response.status === 500) {
throw new Error('Invalid id!');
}
return response.json();
})
.then(data => {
new LoadedPlace(data.coordinates, data.address);
})
.catch(err => {
alert(err.message);
});
Location.js
(前端):
import { key } from '../../key';
export async function getAddressFromCoords(coords) {
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${coords.lat},${coords.lng}&key=${key}`
);
if (!response.ok) {
throw new Error('Failed to fetch address. Please try again!');
}
const data = await response.json();
if (data.error_message) {
throw new Error(data.error_message);
}
const address = data.results[0].formatted_address;
return address;
}
export async function getCoordsFromAddress(address) {
const urlAddress = encodeURI(address);
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?address=${urlAddress}&key=${key}`
);
if (!response.ok) {
throw new Error('Failed to fetch coordinates. Please try again!');
}
const data = await response.json();
if (data.error_message) {
throw new Error(data.error_message);
}
const coordinates = data.results[0].geometry.location;
return coordinates;
}
答: 暂无答案
评论
SharePlace.js
MyPlace.js
Location.js
app.js
GOOGLE_MAPS_API_KEY
SharePlace.js
MyPlace.js