Go后端与React-admin集成时Content-Range Header缺失问题求助
Go+React-admin应用中Content-Range Header缺失导致分页失效问题
我基于Go后端(对接PostgreSQL)和React-admin前端开发应用时遇到问题:React-admin要求的Content-Range Header在API响应中缺失,导致管理面板无法正确展示分页数据。我已在Go接口中尝试设置该Header,但获取用户数据的响应仍未包含它。
Go后端测试API代码
package main import ( "database/sql" "encoding/json" "fmt" "log" "net/http" "github.com/gorilla/mux" _ "github.com/lib/pq" "github.com/rs/cors" ) const ( host = "localhost" port = 5432 user = "postgres" password = "123" dbname = "orbita" ) var db *sql.DB func main() { // Create a connection to the PostgreSQL database connStr := "user=" + user + " password=" + password + " dbname=" + dbname + " sslmode=disable" var err error db, err = sql.Open("postgres", connStr) if err != nil { log.Fatal(err) } defer db.Close() r := mux.NewRouter() // Configure routes for your REST API r.HandleFunc("/users", GetUsers).Methods("GET") // Create a CORS instance c := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, // Allow access from all domains AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"*"}, // Allow all headers }) // Wrap the routes with CORS middleware handler := c.Handler(r) http.Handle("/", handler) http.ListenAndServe(":8080", nil) } // User structure type User struct { Username string `json:"username"` PasswordHash string `json:"password_hash"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Position string `json:"position"` AccessLevel string `json:"access_level"` } // GetUsers returns a list of users from the database func GetUsers(w http.ResponseWriter, r *http.Request) { rows, err := db.Query("SELECT username, password_hash, first_name, last_name, position, access_level FROM users") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() var users []User for rows.Next() { var user User if err := rows.Scan(&user.Username, &user.PasswordHash, &user.FirstName, &user.LastName, &user.Position, &user.AccessLevel); err != nil { log.Println(err) continue } users = append(users, user) } w.Header().Set("Content-Type", "application/json") // Add the Content-Range header in the format 'users 0-24/324' totalUsers := len(users) contentRange := fmt.Sprintf("users 0-%d/%d", totalUsers, totalUsers) w.Header().Set("Content-Range", contentRange) w.WriteHeader(http.StatusOK) responseData := map[string]interface{}{"users": users} json.NewEncoder(w).Encode(responseData) }
React-admin前端代码
App.tsx
import { Admin, Resource } from "react-admin"; import { UserList } from "./users"; import { dataProvider } from "./dataProvider"; export const App = () => <Admin dataProvider={dataProvider}> <Resource name="users" list={UserList} /> </Admin>;
users.tsx
import * as React from 'react'; import { List, Datagrid, TextField, EmailField } from 'react-admin'; export const UserList: React.FC = (props) => ( <List {...props}> <Datagrid rowClick="edit"> <TextField source="username" /> <EmailField source="email" /> <TextField source="first_name" label="First Name" /> <TextField source="last_name" label="Last Name" /> <TextField source="position" /> <TextField source="access_level" label="Access Level" /> </Datagrid> </List> );
问题截图



问题原因与解决方法
CORS配置未暴露自定义Header
rs/cors中间件默认不会将自定义的Content-RangeHeader暴露给前端,需在配置中添加ExposedHeaders字段指定要暴露的Header:c := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowedHeaders: []string{"*"}, ExposedHeaders: []string{"Content-Range"}, // 新增此行,暴露Content-Range })适配React-admin的分页规则与响应格式
React-admin会传递_start和_end分页参数,且要求返回206状态码、顶层数组格式数据,同时Content-Range需符合resource start-end/total规范。修改GetUsers函数:import "strconv" // 需引入strconv包 func GetUsers(w http.ResponseWriter, r *http.Request) { // 解析分页参数,设置默认值 startStr := r.URL.Query().Get("_start") endStr := r.URL.Query().Get("_end") start, err := strconv.Atoi(startStr) if err != nil { start = 0 } end, err := strconv.Atoi(endStr) if err != nil { end = 25 // 默认每页25条 } // 查询总用户数 var totalUsers int err = db.QueryRow("SELECT COUNT(*) FROM users").Scan(&totalUsers) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // 查询指定范围的用户 rows, err := db.Query(` SELECT username, password_hash, first_name, last_name, position, access_level FROM users LIMIT $1 OFFSET $2 `, end-start, start) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() var users []User for rows.Next() { var user User if err := rows.Scan(&user.Username, &user.PasswordHash, &user.FirstName, &user.LastName, &user.Position, &user.AccessLevel); err != nil { log.Println(err) continue } users = append(users, user) } w.Header().Set("Content-Type", "application/json") // 正确设置Content-Range格式 contentRange := fmt.Sprintf("users %d-%d/%d", start, start+len(users)-1, totalUsers) w.Header().Set("Content-Range", contentRange) // 返回React-admin要求的206状态码 w.WriteHeader(http.StatusPartialContent) // 直接返回用户数组,而非嵌套结构 json.NewEncoder(w).Encode(users) }前端字段适配
注意到users.tsx中使用了EmailField绑定email字段,但Go后端的User结构体中无该字段,需确保后端返回数据包含email,或修改前端为TextField避免报错。
内容的提问来源于stack exchange,提问作者Kirill Kolesnikov
相关产品推荐
相关产品推荐

