我在后端使用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
3条答案
按热度按时间h5qlskok1#
原来您使用的是已弃用的软件包
github.com/gin-gonic/contrib/cors
。你应该使用github.com/gin-contrib/cors
。下面是使用github.com/gin-contrib/cors
的演示配置:由于某种原因,
PATCH
请求头缺少“Cookie”头,尽管我使用了withCredentials
参数。这里
{ withCredentials: true }
被当作数据,没有配置。如果你没有数据要发送到服务器,你应该这样写:jckbn6z72#
虽然在这里使用204响应似乎是合适的,但规范有点不清楚,因此您可能需要为选项请求返回200,以使CORS在所有浏览器中工作。
lmvvr0a83#
您在中间件中所做的似乎已经足够,没有任何问题。因为CORS适用于其他方法。
你处理了这个特定的"api.ReturnBookAPI"处理程序中的所有错误了吗?
如果一个请求出错了,它不会正确地返回GIN响应,CORS头不会反映在响应头中。
Content-Length: 0
res中的此字段显示根本没有响应正文检查gin服务日志输出,并确保已打印并检查所有潜在错误。