Golang后端对接Next.js前端API序列化错误及数据获取问题
问题解决及优化方案
一、核心问题定位
报错的直接原因是前端getServerSideProps返回的username为undefined,Next.js要求序列化props时不能存在undefined,必须替换为null或直接省略。而根源是后端接口返回内容不符合预期,前端无法获取有效数据。
二、后端代码修复
1. 修正data.go的GetData函数
当前GetData获取到Pokemon API数据后仅打印,却返回空字符串,导致后端接口无有效数据输出。修改如下:
package main import ( "fmt" "io" "log" "net/http" "os" ) func GetData() string { response, err := http.Get("http://pokeapi.co/api/v2/pokedex/kanto/") if err != nil { fmt.Print(err.Error()) os.Exit(1) } // 关闭响应体,避免资源泄漏 defer response.Body.Close() responseData, err := io.ReadAll(response.Body) if err != nil { log.Fatal(err) } fmt.Println(string(responseData)) // 返回实际获取到的数据 return string(responseData) }
2. 修正Main.go的/username接口逻辑
原代码同时使用json.NewEncoder(rw).Encode(resp)和rw.Write(resp),导致重复输出且格式错误,修改后:
package main import ( "fmt" "log" "net/http" ) func main() { handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Set("Content-Type", "application/json") if req.URL.Path == "/status" { resp := []byte(`{"status": "ok"}`) rw.Header().Set("Content-Length", fmt.Sprint(len(resp))) rw.Write(resp) } else if req.URL.Path == "/username" { data := GetData() rw.Header().Set("Content-Length", fmt.Sprint(len(data))) rw.Write([]byte(data)) } else { rw.WriteHeader(http.StatusNotFound) rw.Write([]byte(`{"error": "not found"}`)) return } }) log.Println("Server is available at http://localhost:8000") log.Fatal(http.ListenAndServe(":8000", handler)) }
注:原代码中
json.NewEncoder会把字节数组再次JSON编码,导致返回内容是字符串形式的字节数组,而非预期的Pokemon API JSON结构,因此必须移除该行。
三、前端代码修复
1. 处理undefined序列化问题
后端返回的是Pokemon图鉴数据,无username字段,前端解构会得到undefined,需设置默认值为null,同时删除无效代码:
export async function getServerSideProps() { const statusResp = await fetch("http://localhost:8000/status").then(x => x.json()); // 捕获接口错误,避免页面崩溃 const pokedexData = await fetch("http://localhost:8000/username") .then(x => x.json()) .catch(() => null); return { props: { status: statusResp.status || null, // 用图鉴名称作为username展示,避免undefined username: pokedexData?.name || null, } } } export default function Home({status, username}: {status: string | null, username: string | null}) { return ( <div className=""> <main className=""> <h1 className=""> Welcome to Next.js! </h1> <div>Status is: {status}, your username is: {username}</div> </main> </div> ) }
四、优化建议
后端优化
- 使用Go 1.16+推荐的
io.ReadAll替代ioutil.ReadAll - 增强错误处理:Pokemon API请求失败时,返回友好的错误JSON,而非直接终止进程
- 拆分路由逻辑,避免单个handler中过多if-else判断,提升代码可维护性
- 添加CORS配置,避免跨域问题(若前后端部署在不同域名)
前端优化
- 为fetch添加完整的错误捕获逻辑,避免接口失败导致页面崩溃
- 明确类型定义,放弃
any类型,使用string | null这类具体类型 - 将API请求封装为独立函数,便于复用和统一维护
- 考虑使用SWR或React Query实现数据缓存和自动刷新,提升用户体验
内容的提问来源于stack exchange,提问作者Carlos
相关产品推荐
相关产品推荐

