为什么使用 react-admin 为 API 端点获取 404?
Why got 404 for API endpoint with react-admin?
已创建后端 API 使用 gin
和 go
语言
type Post struct {
ID uint `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func main() {
// ...
r := gin.Default()
r.GET("/posts", GetPosts)
r.GET("/posts/:id", GetPost)
r.POST("/posts", CreatePost)
r.PUT("/posts/:id", UpdatePost)
r.DELETE("/posts/:id", DeletePost)
r.Run(":8080")
}
func GetPosts(c *gin.Context) {
var posts []Post
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
if err := db.Find(&posts).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, post)
}
}
// ...
创建的前端使用 react
和 react-admin
src/App.js
import React from 'react';
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { PostList } from './posts';
const dataProvider = jsonServerProvider('http://localhost:8080');
const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts" list={PostList} />
</Admin>
);
export default App;
src/posts.js
import React from 'react';
import { List, Datagrid, TextField } from 'react-admin';
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="body" />
</Datagrid>
</List>
);
当从 chrome 浏览器访问 http://localhost:3000
时,收到 Failed to fetch
消息。从控制台我看到:
Failed to load http://localhost:8080/posts?_end=10&_order=DESC&_sort=id&_start=0: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 404. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
我试过在goAPI程序中加入Access-Control-Allow-Origin
,结果一样。从 gin
输出我得到:
[GIN] 2018/06/12 - 18:14:50 | 404 | 1.813µs | 127.0.0.1 | OPTIONS /posts?_end=10&_order=DESC&_sort=id&_start=0
添加
添加了 cors
包然后将源更改为:
package main
import (
"fmt"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
// ...
)
// ...
func main() {
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:8080"},
}))
r.GET("/posts", GetPosts)
r.GET("/posts/:id", GetPost)
r.POST("/posts", CreatePost)
r.PUT("/posts/:id", UpdatePost)
r.DELETE("/posts/:id", DeletePost)
r.Run()
}
再次遇到同样的错误:
Failed to load http://localhost:8080/posts?_end=10&_order=DESC&_sort=id&_start=0: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
这一次,gin
的输出是:
[GIN] 2018/06/13 - 11:01:59 | 403 | 7.873µs | ::1 | OPTIONS /posts?_end=10&_order=DESC&_sort=id&_start=0
为跨源域请求添加CORS
中间件。我更愿意使用 postman
来点击 api 来检查它是否工作正常。下面是在go中为gin实现CORS
中间件的方法:-
package main
import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// CORS for http://localhost:8080 and https://github.com origins, allowing:
// - PUT and PATCH methods
// - Origin header
// - Credentials share
// - Preflight requests cached for 12 hours
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:8080, https://localhost:8080"},
AllowMethods: []string{"GET", "POST", "HEAD", "PUT", "PATCH"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
router.Run()
}
已编辑: 允许所有来源使用 Default
配置 cors
as
func main() {
router := gin.Default()
// same as
// config := cors.DefaultConfig()
// config.AllowAllOrigins = true
// router.Use(cors.New(config))
router.Use(cors.Default())
router.Run()
}
有关杜松子酒
的更多信息,请查看CORS middleware
这种方式可行:
func main() {
// ...
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type"},
ExposeHeaders: []string{"X-Total-Count"},
}))
r.GET("/posts", GetPosts)
// ...
r.Run()
}
func GetPosts(c *gin.Context) {
var posts []Post
if err := db.Find(&posts).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.Header("X-Total-Count", "25")
c.JSON(200, posts)
}
}
已创建后端 API 使用 gin
和 go
语言
type Post struct {
ID uint `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
}
func main() {
// ...
r := gin.Default()
r.GET("/posts", GetPosts)
r.GET("/posts/:id", GetPost)
r.POST("/posts", CreatePost)
r.PUT("/posts/:id", UpdatePost)
r.DELETE("/posts/:id", DeletePost)
r.Run(":8080")
}
func GetPosts(c *gin.Context) {
var posts []Post
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
if err := db.Find(&posts).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.JSON(200, post)
}
}
// ...
创建的前端使用 react
和 react-admin
src/App.js
import React from 'react';
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { PostList } from './posts';
const dataProvider = jsonServerProvider('http://localhost:8080');
const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts" list={PostList} />
</Admin>
);
export default App;
src/posts.js
import React from 'react';
import { List, Datagrid, TextField } from 'react-admin';
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="body" />
</Datagrid>
</List>
);
当从 chrome 浏览器访问 http://localhost:3000
时,收到 Failed to fetch
消息。从控制台我看到:
Failed to load http://localhost:8080/posts?_end=10&_order=DESC&_sort=id&_start=0: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 404. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
我试过在goAPI程序中加入Access-Control-Allow-Origin
,结果一样。从 gin
输出我得到:
[GIN] 2018/06/12 - 18:14:50 | 404 | 1.813µs | 127.0.0.1 | OPTIONS /posts?_end=10&_order=DESC&_sort=id&_start=0
添加
添加了 cors
包然后将源更改为:
package main
import (
"fmt"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
// ...
)
// ...
func main() {
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:8080"},
}))
r.GET("/posts", GetPosts)
r.GET("/posts/:id", GetPost)
r.POST("/posts", CreatePost)
r.PUT("/posts/:id", UpdatePost)
r.DELETE("/posts/:id", DeletePost)
r.Run()
}
再次遇到同样的错误:
Failed to load http://localhost:8080/posts?_end=10&_order=DESC&_sort=id&_start=0: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
这一次,gin
的输出是:
[GIN] 2018/06/13 - 11:01:59 | 403 | 7.873µs | ::1 | OPTIONS /posts?_end=10&_order=DESC&_sort=id&_start=0
为跨源域请求添加CORS
中间件。我更愿意使用 postman
来点击 api 来检查它是否工作正常。下面是在go中为gin实现CORS
中间件的方法:-
package main
import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
// CORS for http://localhost:8080 and https://github.com origins, allowing:
// - PUT and PATCH methods
// - Origin header
// - Credentials share
// - Preflight requests cached for 12 hours
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:8080, https://localhost:8080"},
AllowMethods: []string{"GET", "POST", "HEAD", "PUT", "PATCH"},
AllowHeaders: []string{"Origin"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
router.Run()
}
已编辑: 允许所有来源使用 Default
配置 cors
as
func main() {
router := gin.Default()
// same as
// config := cors.DefaultConfig()
// config.AllowAllOrigins = true
// router.Use(cors.New(config))
router.Use(cors.Default())
router.Run()
}
有关杜松子酒
的更多信息,请查看CORS middleware这种方式可行:
func main() {
// ...
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type"},
ExposeHeaders: []string{"X-Total-Count"},
}))
r.GET("/posts", GetPosts)
// ...
r.Run()
}
func GetPosts(c *gin.Context) {
var posts []Post
if err := db.Find(&posts).Error; err != nil {
c.AbortWithStatus(404)
fmt.Println(err)
} else {
c.Header("X-Total-Count", "25")
c.JSON(200, posts)
}
}