You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中使用FullCalendar时安全调用Google Calendar API的密钥问题

解决方案:通过Next.js API路由代理保护Google Calendar API密钥

要在Next.js中安全使用FullCalendar对接Google Calendar,核心思路是用服务器端API路由作为代理,避免在客户端直接暴露API密钥。具体步骤如下:

1. 创建服务器端API代理路由

在Next.js项目中创建API路由(Pages Router用pages/api/calendar-events.js,App Router用app/api/calendar-events/route.js),负责从Google Calendar API拉取事件并返回给客户端:

Pages Router 示例(pages/api/calendar-events.js)

import axios from 'axios';

export default async function handler(req, res) {
  const { GOOGLE_CALENDAR_API_KEY, GOOGLE_CALENDAR_ID } = process.env;
  if (!GOOGLE_CALENDAR_API_KEY || !GOOGLE_CALENDAR_ID) {
    return res.status(500).json({ error: 'Missing environment variables' });
  }

  try {
    const response = await axios.get(
      `https://www.googleapis.com/calendar/v3/calendars/${GOOGLE_CALENDAR_ID}/events`,
      {
        params: {
          key: GOOGLE_CALENDAR_API_KEY,
          singleEvents: true,
          orderBy: 'startTime',
          // 可根据需求添加其他参数,比如时间范围
        },
      }
    );

    // 转换Google Calendar事件格式适配FullCalendar
    const events = response.data.items.map(event => ({
      id: event.id,
      title: event.summary,
      start: event.start.dateTime || event.start.date,
      end: event.end.dateTime || event.end.date,
      description: event.description,
      // 其他需要的字段
    }));

    res.status(200).json(events);
  } catch (error) {
    res.status(error.response?.status || 500).json({ error: error.message });
  }
}

App Router 示例(app/api/calendar-events/route.js)

import axios from 'axios';
import { NextResponse } from 'next/server';

export async function GET() {
  const { GOOGLE_CALENDAR_API_KEY, GOOGLE_CALENDAR_ID } = process.env;
  if (!GOOGLE_CALENDAR_API_KEY || !GOOGLE_CALENDAR_ID) {
    return NextResponse.json({ error: 'Missing environment variables' }, { status: 500 });
  }

  try {
    const response = await axios.get(
      `https://www.googleapis.com/calendar/v3/calendars/${GOOGLE_CALENDAR_ID}/events`,
      {
        params: {
          key: GOOGLE_CALENDAR_API_KEY,
          singleEvents: true,
          orderBy: 'startTime',
        },
      }
    );

    const events = response.data.items.map(event => ({
      id: event.id,
      title: event.summary,
      start: event.start.dateTime || event.start.date,
      end: event.end.dateTime || event.end.date,
      description: event.description,
    }));

    return NextResponse.json(events);
  } catch (error) {
    return NextResponse.json(
      { error: error.message },
      { status: error.response?.status || 500 }
    );
  }
}

2. 修改FullCalendar组件配置

不再使用googleCalendarPlugin,而是通过自定义逻辑请求我们的API路由,同时保留原有的UI逻辑:

import { useState, useEffect } from 'react';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import listPlugin from '@fullcalendar/list';
import Tooltip from '@mui/material/Tooltip';

const Calendar = () => {
  const [events, setEvents] = useState([]);

  useEffect(() => {
    // 从API路由获取事件
    fetch('/api/calendar-events')
      .then(res => res.json())
      .then(data => setEvents(data))
      .catch(err => console.error('Failed to fetch events:', err));
  }, []);

  const renderInnerContent = (arg) => {
    return <div>{arg.event.title}</div>; // 替换成你原来的渲染逻辑
  };

  return (
    <FullCalendar
      eventContent={(arg) => {
        return (
          <Tooltip title={arg.event.description} arrow>
            {renderInnerContent(arg)}
          </Tooltip>
        );
      }}
      headerToolbar={{
        start: "title",
        center: "dayGridMonth,listMonth",
        end: "today prev,next", 
      }}
      plugins={[dayGridPlugin, listPlugin]} // 移除googleCalendarPlugin
      initialView="listMonth"
      eventDisplay="block"
      weekends={false}
      events={events} // 使用从API获取的事件数据
    />
  );
};

export default Calendar;

3. 配置环境变量

在.env.local中添加密钥(注意不要加NEXT_PUBLIC_前缀,确保只有服务器端能访问):

GOOGLE_CALENDAR_API_KEY=your_actual_api_key
GOOGLE_CALENDAR_ID=your_calendar_id@group.calendar.google.com

额外安全建议

  • 给Google API密钥设置应用限制:在Google Cloud控制台中,限制该密钥仅能调用Google Calendar API,并设置HTTP referrer限制为你的域名(比如https://your-domain.com/*),即使密钥意外泄露,攻击者也无法在其他域名使用。
  • 确保你的Google Calendar确实设置为公开访问,否则服务器端请求也会失败。

内容的提问来源于stack exchange,提问作者marcusArcus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:35:51