在 React 后我开始进入后端,并在后端服务器上添加了 github OAUTH 和会话来保存数据。它们在后端都工作正常,我可以通过会话等从其他处理程序访问数据。但是一旦我尝试使用 React 从后端获取会话,我就永远无法做到这一点。
func (h Handler) HandleAuth(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:5173") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") w.Header().Set("Access-Control-Allow-Methods", "GET") url := Oauth2Config.AuthCodeURL("state", oauth2.AccessTypeOffline) http.Redirect(w, r, url, http.StatusFound) } func (h Handler) HandleAuthCallback(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:5173") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") w.Header().Set("Access-Control-Allow-Methods", "GET") code := r.URL.Query().Get("code") token, err := Oauth2Config.Exchange(r.Context(), code) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Use the access token to get the user's GitHub data client := github2.NewTokenClient(r.Context(), token.AccessToken) user, _, err := client.Users.Get(r.Context(), "") if err != nil { fmt.Printf("Error: %v\n", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) return } session, err := store.Get(r, "session") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } session.Values["user"] = user.GetLogin() session.Values["access_token"] = token.AccessToken err = session.Save(r, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } fmt.Fprintf(w, "this is authcallback: %s", user.GetLogin()) } func (h Handler) HandleCurrentUser(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "http://localhost:5173") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") w.Header().Set("Access-Control-Allow-Methods", "GET") session, err := store.Get(r, "session") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } user, ok := session.Values["user"].(string) if !ok { http.Error(w, "Invalid user in session", http.StatusInternalServerError) return } // Set the content type header to JSON w.Header().Set("Content-Type", "text/plain") // Write the JSON data to the response w.Write([]byte(user)) }
我尝试了很多东西,首先我使用了一个不同于 gorilla 的会话库,它被称为 scs,我想这可能是我的库,但事实并非如此。在更改代码时,我得到的错误有所不同,但每次后端都工作正常。在来自后端的 API 请求上,有时我会得到一个空字符串数据,或者网络错误或找不到用户等,但每次我在代码后端的每次迭代中检查后端时都工作得很好。这是获取请求:
function App() { const [user, setUser] = useState(null); useEffect(() => { fetch('http://127.0.0.1:3080/user', { method: 'GET', }) .then(response => response.text()) .then(data => { setUser(data); console.log(data); }) .catch(error => console.error(error)); }, []); []); return <> <p>Logged in as: {user}</p> <button onClick={() => window.location.href = 'http://127.0.0.1:3080/oauth'}>Login</button> </> }
P粉2370294572024-04-07 00:04:59
IIUC,网页从 http://localhost:5173
加载,并向 http://127.0.0.1:3080/user
发出 GET 请求。所以这是一个跨源请求。
默认情况下,在跨源 XMLHttpRequest 或 Fetch 调用中,浏览器不会发送凭据(例如 Cookie 和 HTTP 身份验证< /a>)。调用 XMLHttpRequest 对象或 Request 构造函数时,必须设置特定标志。
为了告诉浏览器将 cookie 发送到跨域 URL,应该像这样更改 fetch 调用:
fetch('http://127.0.0.1:3080/user', { method: 'GET', + mode: 'cors', + credentials: 'include', })
有关详细信息,请参阅带有凭据的请求.
看起来后端代码已正确配置 CORS 标头,因此上述更改应该可以使其正常工作。如果没有,请检查浏览器的 DevTools 控制台。它应该包含一些错误/警告消息,告诉您出了什么问题。
这是有助于调试问题的最小演示。
启动服务器:go run main.go
在浏览器中导航至 http://127.0.0.1:3080/callback
以设置 cookie。
Set-Cookie: session=abc;路径=/;过期=2023 年 4 月 18 日星期二 18:34:49 GMT;最大年龄=86372;仅 Http; SameSite=Lax
。
导航到 http://127.0.0.1:5173/
打开页面。
单击此页面上的获取按钮。它应该将会话 cookie“abc”输出到 DevTools 控制台。
注释:
我刚刚意识到cookie被保存到域127.0.0.1
(没有端口)。所以http://127.0.0.1:5173/
页面也可以读取cookie。
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
go func() {
_ = http.ListenAndServe(":5173", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(page))
}))
}()
http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{
Name: "session",
Value: "abc",
Path: "/",
Expires: time.Now().Add(24 * time.Hour),
MaxAge: 86372,
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
})
w.Write([]byte("done"))
})
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:5173")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Header().Set("Access-Control-Allow-Credentials", "true")
cookie, err := r.Cookie("session")
if err != nil {
fmt.Fprintln(w, err.Error())
return
}
w.Write([]byte(cookie.Value))
})
http.ListenAndServe(":3080", nil)
}
const page = `
sssccc
`
隐身窗口无法看到其他窗口的 cookie。请检查浏览器以确保 cookie 存在。