Go语言 CORS政策:对印前检查请求的响应未通过访问控制检查:无“Access-Control-Allow-Origin”

cedebl8k  于 2023-06-19  发布在  Go
关注(0)|答案(3)|浏览(151)

我在后端使用gin-gonic/gin web框架,在前端使用React 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.

这个错误只在我尝试发送PATCH请求时发生,所以需要preflight OPTIONS请求的请求,但对于GET和POST,一切都按预期工作,不运行任何preflight检查。
下面是我的路由器配置代码:

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

而对于PATCH请求尝试,我没有任何响应(这并不奇怪),并且preflight响应头部是:

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

你有什么建议可能是什么问题?这两天,我已经不知道了。感谢您的评分
我也试着写了header:

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
    }

但一点用都没有。事实上,在执行预检时,if语句并不执行,我从控制台知道服务器正在执行OPTIONS请求。

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

编辑:
下面是发送PATCH请求的cURL命令(实际上这里是preflight OPTIONS请求):

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
h5qlskok

h5qlskok1#

原来您使用的是已弃用的软件包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")
}

由于某种原因,PATCH请求头缺少“Cookie”头,尽管我使用了withCredentials参数。

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

这里{ withCredentials: true }被当作数据,没有配置。如果你没有数据要发送到服务器,你应该这样写:

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

jckbn6z72#

虽然在这里使用204响应似乎是合适的,但规范有点不清楚,因此您可能需要为选项请求返回200,以使CORS在所有浏览器中工作。

lmvvr0a8

lmvvr0a83#

您在中间件中所做的似乎已经足够,没有任何问题。因为CORS适用于其他方法。
你处理了这个特定的"api.ReturnBookAPI"处理程序中的所有错误了吗?
如果一个请求出错了,它不会正确地返回GIN响应,CORS头不会反映在响应头中。
Content-Length: 0 res中的此字段显示根本没有响应正文
检查gin服务日志输出,并确保已打印并检查所有潜在错误。

相关问题