我在后端使用Golang,在后端使用Gin-Gonic/Gin网络框架,在我的前端使用Reaction Axios.我已经试了两天了,但仍然得到以下相同的错误:

CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

仅当我try 发送修补程序请求时才会出现此错误,因此需要印前判断选项请求,但GET和POST的一切工作正常,这两个请求不会运行任何印前判断.

以下是我的路由配置代码:

package main

import (
    "book_renting/api"
    "log"
    "net/http"

    "github.com/gin-contrib/sessions"
    "github.com/gin-contrib/sessions/cookie"
    "github.com/gin-gonic/contrib/cors"
    "github.com/gin-gonic/gin"
    _ "github.com/lib/pq"
)

func main() {

    router := gin.Default()
    store := cookie.NewStore([]byte("your-secret-key"))
    store.Options(sessions.Options{MaxAge: 60 * 60 * 24})

    router.Use(cors.Default())
    router.Use(sessions.Sessions("sessions", store))

    router.Use(func(c *gin.Context) {
        host := c.Request.Header.Get("Origin")
        c.Writer.Header().Set("Access-Control-Allow-Origin", host)
        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
        if c.Request.Method == "OPTIONS" {
            log.Println("Handling OPTIONS request")
            c.AbortWithStatus(http.StatusNoContent)
            return
        }
        log.Println("Executing CORS middleware")
        c.Next()
    })

    router.POST("/login", api.HandleLogin)
    router.GET("/logout", api.HandleLogout)
    router.POST("/register", api.HandleRegister)
    router.GET("/getCookie", api.GetCookieSession)

    router.GET("/books", api.GetBooksAPI)
    router.GET("/books/:id", api.BookByIdAPI)
    router.PATCH("/rent/:id", api.RentBookAPI)
    router.PATCH("/return/:id", api.ReturnBookAPI)
    router.Run("localhost:3000")
}

下面是前端部分:

import axios from 'axios'

const url = 'http://localhost:3000'

export const loginUser = async (credentials) => await axios.post(`${url}/login`, credentials, {withCredentials: true})
export const logoutUser = async () => await axios.get(`${url}/logout`, {withCredentials: true})
export const registerUser = () => axios.post(`${url}/register`)
export const fetchBooks = () => axios.get(`${url}/books`, { withCredentials: true })
export const fetchBookByID = (book_id) => axios.get(`${url}/books/${book_id}`, { withCredentials: true })
export const rentBook = (book_id) => axios.patch(`${url}/rent/${book_id}`, { withCredentials: true })
export const returnBook = (book_id) => axios.patch(`${url}/return/${book_id}`, { withCredentials: true })

我非常确定我正确地设置了后端,它应该返回所有必要的标头.

例如,对于GET请求,响应头如下所示:

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Origin: http://localhost:3001
Content-Type: application/json; charset=utf-8
Date: Sat, 10 Jun 2023 22:12:11 GMT
Content-Length: 495

而对于修补程序请求try ,我没有任何响应(这并不奇怪),印前判断响应标头为:

HTTP/1.1 200 OK
Date: Sat, 10 Jun 2023 22:12:12 GMT
Content-Length: 0

你有什么建议可能是这个问题吗?过了这两天,我已经一窍不通了.提前谢谢您!

我还试着把标题放在:

c.Writer.Header().Set("Access-Control-Allow-Origin", host)
        c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")

...再次在if语句中:

if c.Request.Method == "OPTIONS" {
    log.Println("Handling OPTIONS request")
    c.AbortWithStatus(http.StatusNoContent)
    return
    }

但这丝毫没有帮助.事实上,当执行印前判断时,并且我从控制台知道服务器正在执行OPTIONS请求时,不会执行此if语句.

[GIN] 2023/06/11 - 00:12:13 | 200 |       7.708µs |       127.0.0.1 | OPTIONS  "/rent/2"

编辑:

下面是发送修补程序请求的curl命令(因此,实际上这里是印前判断选项请求):

curl 'http://localhost:3000/return/2' \
  -X 'OPTIONS' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7' \
  -H 'Access-Control-Request-Headers: content-type' \
  -H 'Access-Control-Request-Method: PATCH' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: keep-alive' \
  -H 'Origin: http://localhost:3001' \
  -H 'Pragma: no-cache' \
  -H 'Referer: http://localhost:3001/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-site' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
  --compressed

对这一请求的回应是:

HTTP/1.1 200 OK
Date: Sun, 11 Jun 2023 01:22:57 GMT
Content-Length: 0

推荐答案

原来您使用的是不推荐使用的包github.com/gin-gonic/contrib/cors.你应该用github.com/gin-contrib/cors代替.以下是使用github.com/gin-contrib/cors的演示配置:

package main

import (
    "github.com/gin-contrib/cors"
    "github.com/gin-contrib/sessions"
    "github.com/gin-contrib/sessions/cookie"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    config := cors.DefaultConfig()
    config.AddAllowHeaders("Authorization")
    config.AllowCredentials = true
    config.AllowAllOrigins = false
    // I think you should whitelist a limited origins instead:
    //  config.AllowAllOrigins = []{"xxxx", "xxxx"}
    config.AllowOriginFunc = func(origin string) bool {
        return true
    }
    router.Use(cors.New(config))

    store := cookie.NewStore([]byte("your-secret-key"))
    store.Options(sessions.Options{MaxAge: 60 * 60 * 24})
    router.Use(sessions.Sessions("sessions", store))

    // routes below

    router.Run("localhost:3000")
}

尽管我使用了withCredentials参数,但由于某种原因,PATCH请求标头缺少"Cookie"标头.

axios.patch(`${url}/rent/${book_id}`, { withCredentials: true })

这里将{ withCredentials: true }作为数据处理,没有配置.如果您没有要发送到服务器的数据,则应该这样编写:

axios.patch(`${url}/rent/${book_id}`, null, { withCredentials: true })

Reactjs相关问答推荐

如何通过TEK查询将对象传递到Express后台

有正确的方法来设置我的金牛座应用程序的图标吗?

安装后未渲染tailwind

如何在NextJS中仅在刷新页面和页面淡出页面过渡时添加全屏加载器

在数组对象内的数组上进行映射

Reaction Google Maps API无法获取标题

这两个子元素在Reaction Native中使用的有什么不同?

错误:操作必须是普通对象.使用自定义中间件进行异步操作. Redux/工具包

设置自定义形状的纹理

Chakra UI:如何在选中状态下设置复选框 colored颜色

redux 工具包使用中间件构建器函数时,必须返回一个中间件数组

在 React-Select 中显示多值的倒序

如何使用样式化函数为 TextField 的输入组件设置样式

在准备回调中使用状态属性(Redux 工具包)

为什么接受 useState 返回的函数的 setter 在使用 React 的单个调用中执行两次?

如何向 surveyjs 调查添加多个结尾?

为什么此代码中的 useState 不更新(文本更新但 id 不更新)?

getAttribute 函数并不总是检索属性值

使用 React 中的功能组件更改另一个组件的状态

无法重用我的组件,它只显示 1 次