如何在Next.js应用中从Hono API端点实现类型安全的数据获取?
在Next.js中实现跨子域名访问Hono API的类型安全数据获取
1. 在Hono API端导出类型并配置CORS
首先在你的Hono+Bun API项目中,定义路由并导出API的类型,同时配置CORS允许Next.js子域名访问:
// api/src/index.ts import { Hono } from 'hono' import { cors } from 'hono/cors' const app = new Hono() // 配置CORS,允许portal.example.com跨域访问 app.use('*', cors({ origin: 'https://portal.example.com', credentials: true // 需要传递Cookie/认证信息时开启 })) // 定义API路由 app.get('/api/users', (c) => { return c.json({ id: 1, name: 'John Doe', email: 'john@example.com' }) }) app.post('/api/users', async (c) => { const body = await c.req.json<{ name: string; email: string }>() return c.json({ id: Date.now(), ...body }, 201) }) // 导出API的完整类型(替代找不到的AppType) export type ApiType = typeof app export default app
2. 共享API类型到Next.js项目
将Hono项目中导出的ApiType共享给Next.js项目,推荐三种方式:
- 本地链接:用Bun/npm的
link命令将API项目作为本地依赖关联到Next.js项目 - 共享类型文件:将类型单独抽成文件,复制到Next.js项目或通过Git Submodule管理
- 私有npm包:将API类型发布到私有仓库,Next.js项目安装依赖
示例假设两个项目在同一目录下,直接通过相对路径导入类型:
项目结构 ├── api/ # Hono+Bun API项目 │ └── src/ │ └── index.ts └── nextjs/ # Next.js项目 └── app/ ├── lib/ │ └── api-client.ts └── page.tsx
3. 在Next.js中创建类型安全的API客户端
使用Hono的createClient工具生成类型安全的客户端,自动关联API路由和返回类型:
// nextjs/app/lib/api-client.ts import { createClient } from 'hono/client' // 导入Hono API导出的类型 import type { ApiType } from '../../../api/src/index' // 创建客户端,指定API基础域名 const apiClient = createClient<ApiType>({ baseURL: 'https://api.example.com' }) // 封装业务API调用函数 export const api = { getUser: async () => { const res = await apiClient.api.users.$get() if (!res.ok) throw new Error('获取用户失败') return res.json() }, createUser: async (userData: { name: string; email: string }) => { const res = await apiClient.api.users.$post({ json: userData }) if (!res.ok) throw new Error('创建用户失败') return res.json() } }
4. 在Next.js组件中使用类型安全的API调用
Server Component 示例
// nextjs/app/page.tsx import { api } from './lib/api-client' export default async function Home() { // Server Component中直接调用API const user = await api.getUser() return ( <div className="container"> <h1>当前用户:{user.name}</h1> <p>邮箱:{user.email}</p> </div> ) }
Client Component 示例
// nextjs/app/components/CreateUser.tsx 'use client' import { useState } from 'react' import { api } from '../lib/api-client' export default function CreateUser() { const [name, setName] = useState('') const [email, setEmail] = useState('') const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() try { const newUser = await api.createUser({ name, email }) alert(`用户创建成功:${newUser.name}`) } catch (err) { alert((err as Error).message) } } return ( <form onSubmit={handleSubmit}> <input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="姓名" required /> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="邮箱" required /> <button type="submit">创建用户</button> </form> ) }
关键说明
- 替代AppType:新版Hono已不再使用
AppType,直接通过typeof app导出API的完整类型即可 - 跨域保障:必须在Hono端配置CORS指定允许的Next.js子域名,否则浏览器会拦截跨域请求
- 版本一致性:确保Next.js和Hono项目使用相同版本的Hono依赖,避免类型不兼容
内容的提问来源于stack exchange,提问作者hantoren
相关产品推荐
相关产品推荐

