NextJS:如何将ReadableStream<Uint8Array>导入NextApiResponse并代理谷歌图片
解决Next.js API路由转发Google Place图片的问题
核心问题分析
你之前的尝试失败主要有两个原因:
- Google Place Photo API必须指定
maxwidth或maxheight参数,你的请求URL缺少这个必填项,导致API返回错误 - 对Next.js API路由的响应流处理方式错误,不同Runtime(Node.js/Edge)的流处理逻辑不同
解决方案
1. Pages Router(Node.js Runtime)
创建pages/api/photos/[photoRef].ts文件,代码如下:
import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { // 从URL参数获取图片引用ID const photoRef = req.query.photoRef as string; if (!photoRef) { return res.status(400).send('缺少图片引用ID'); } const apiKey = process.env.GOOGLE_PLACE_API_KEY; if (!apiKey) { return res.status(500).send('未配置Google API密钥'); } // 构建合规的Google图片请求URL const googleUrl = new URL('https://maps.googleapis.com/maps/api/place/photo'); googleUrl.searchParams.set('photo_reference', photoRef); googleUrl.searchParams.set('maxwidth', '800'); // 根据需求调整尺寸 googleUrl.searchParams.set('key', apiKey); try { const googleRes = await fetch(googleUrl.toString()); if (!googleRes.ok) { console.error('Google API请求失败:', googleRes.status, googleRes.statusText); return res.status(googleRes.status).send('获取图片失败'); } // 复制Google响应的关键头信息 const contentType = googleRes.headers.get('Content-Type'); const contentLength = googleRes.headers.get('Content-Length'); if (contentType) res.setHeader('Content-Type', contentType); if (contentLength) res.setHeader('Content-Length', contentLength); // Node.js环境下直接将响应流管道到前端 (googleRes.body as any).pipe(res); } catch (err) { console.error('转发图片出错:', err); res.status(500).send('服务器内部错误'); } }
2. App Router(Edge Runtime)
创建app/api/photos/[photoRef]/route.ts文件,代码如下:
import type { NextRequest } from 'next/server'; export const runtime = 'edge'; // 指定使用Edge Runtime export async function GET(request: NextRequest) { // 从URL路径提取图片引用ID const photoRef = request.nextUrl.pathname.split('/').pop(); if (!photoRef) { return new Response('缺少图片引用ID', { status: 400 }); } const apiKey = process.env.GOOGLE_PLACE_API_KEY; if (!apiKey) { return new Response('未配置Google API密钥', { status: 500 }); } // 构建合规的Google图片请求URL const googleUrl = new URL('https://maps.googleapis.com/maps/api/place/photo'); googleUrl.searchParams.set('photo_reference', photoRef); googleUrl.searchParams.set('maxwidth', '800'); googleUrl.searchParams.set('key', apiKey); const googleRes = await fetch(googleUrl.toString()); if (!googleRes.ok) { return new Response('获取图片失败', { status: googleRes.status }); } // Edge Runtime直接转发Google的响应流 return new Response(googleRes.body, { headers: { 'Content-Type': googleRes.headers.get('Content-Type') || 'image/jpeg', 'Content-Length': googleRes.headers.get('Content-Length') || '', }, }); }
前端使用方式
直接按你的需求调用API即可:
<img src={`/api/photos/${place?.photos[0].photo_reference}`} alt="地点图片" />
内容的提问来源于stack exchange,提问作者HarrisR
相关产品推荐
相关产品推荐

