英文:
HTTP redirect not rendering new page
问题
我有用户登录页面。当他们成功登录后,应该将他们重定向到用户页面。然而,这并没有发生,我不确定原因。似乎ajax调用由于某种原因进入了错误状态(我不确定原因)。但是,当我记录响应时,可以看到新页面已经在响应文本中传递过来。
登录方法应该重定向用户:
// 这个映射存储用户的会话。对于规模较大的应用程序,您可以使用数据库或缓存来实现此目的
var sessions = map[string]session{}
// 每个会话包含用户的用户名和过期时间
type session struct {
username string
expiry time.Time
}
// 我们稍后将使用此方法来确定会话是否已过期
func (s session) isExpired() bool {
return s.expiry.Before(time.Now())
}
// 凭据 创建一个模拟请求体中用户结构的结构体
type Credentials struct {
Password string `json:"password"`
Username string `json:"username"`
}
func login(w http.ResponseWriter, r *http.Request) {
log.Println("login started")
var creds Credentials
// 获取JSON主体并解码为凭据
if err := json.NewDecoder(r.Body).Decode(&creds); err != nil {
// 如果主体的结构不正确,则返回HTTP错误
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
// 从内存映射中获取预期的密码
expectedPassword, ok := "test", true
// 如果给定用户存在密码
// 并且,如果它与我们收到的密码相同,则我们可以继续
// 如果不是,则返回“未经授权”状态
if !ok || expectedPassword != creds.Password {
log.Println("bad password")
w.WriteHeader(http.StatusUnauthorized)
return
}
// 创建一个新的随机会话令牌
// 我们使用“github.com/google/uuid”库生成UUID
sessionToken := uuid.NewString()
expiresAt := time.Now().Add(120 * time.Second)
// 在会话映射中设置令牌,以及会话信息
sessions[sessionToken] = session{
username: creds.Username,
expiry: expiresAt,
}
// 最后,我们将客户端cookie设置为“session_token”,值为刚生成的会话令牌
// 我们还设置了120秒的过期时间
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: sessionToken,
Expires: expiresAt,
})
log.Println("login success")
http.Redirect(w, r, "/users", http.StatusFound)
}
Ajax调用:
function handleSubmit(evt) {
evt.preventDefault();
let form = evt.target;
let data = new FormData(form);
if (data.get("username") != null && data.get("username") != "") {
$.ajax({
url: '/login',
method: 'post',
data: JSON.stringify(Object.fromEntries(data)),
dataType: 'json',
success: (resp) => {
if (resp.redirect) {
// resp.redirect包含要重定向到的字符串URL
window.location.redirect = resp.redirect;
}
},
error: (resp) => {
console.log("An error occurred. Please try again");
console.log(resp)
}
});
}
return false
}
英文:
I have the users landing on a login page. When they successfully login, this should then redirect them to the users page. However this is not happening and am unsure why. It seems as though the ajax call is going into the error for some reason (Am unsure as to why). I can see though when I log the response that the new page has come through in the response text.
login method that should redirect user:
// this map stores the users sessions. For larger scale applications, you can use a database or cache for this purpose
var sessions = map[string]session{}
// each session contains the username of the user and the time at which it expires
type session struct {
username string
expiry time.Time
}
// we'll use this method later to determine if the session has expired
func (s session) isExpired() bool {
return s.expiry.Before(time.Now())
}
// Credentials Create a struct that models the structure of a user in the request body
type Credentials struct {
Password string `json:"password"`
Username string `json:"username"`
}
func login(w http.ResponseWriter, r *http.Request) {
log.Println("login started")
var creds Credentials
// Get the JSON body and decode into credentials
if err := json.NewDecoder(r.Body).Decode(&creds); err != nil {
// If the structure of the body is wrong, return an HTTP error
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
// Get the expected password from our in memory map
expectedPassword, ok := "test", true
// If a password exists for the given user
// AND, if it is the same as the password we received, then we can move ahead
// if NOT, then we return an "Unauthorized" status
if !ok || expectedPassword != creds.Password {
log.Println("bad password")
w.WriteHeader(http.StatusUnauthorized)
return
}
// Create a new random session token
// we use the "github.com/google/uuid" library to generate UUIDs
sessionToken := uuid.NewString()
expiresAt := time.Now().Add(120 * time.Second)
// Set the token in the session map, along with the session information
sessions[sessionToken] = session{
username: creds.Username,
expiry: expiresAt,
}
// Finally, we set the client cookie for "session_token" as the session token we just generated
// we also set an expiry time of 120 seconds
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: sessionToken,
Expires: expiresAt,
})
log.Println("login success")
http.Redirect(w, r, "/users", http.StatusFound)
}
Ajax call:
function handleSubmit(evt) {
evt.preventDefault();
let form = evt.target;
let data = new FormData(form);
if (data.get("username") != null && data.get("username") != "") {
$.ajax({
url: '/login',
method: 'post',
data: JSON.stringify(Object.fromEntries(data)),
dataType: 'json',
success: (resp) => {
if (resp.redirect) {
// resp.redirect contains the string URL to redirect to
window.location.redirect = resp.redirect;
}
},
error: (resp) => {
console.log("An error occurred. Please try again");
console.log(resp)
}
});
}
return false
}
答案1
得分: 0
为了解决您的问题,您需要稍微修改一下服务器代码。
func login(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
log.Println("login started")
var creds Credentials
// 获取JSON主体并解码为凭据
if err := json.NewDecoder(r.Body).Decode(&creds); err != nil {
// 如果主体的结构有误,则返回HTTP错误
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
// 从内存映射中获取预期的密码
expectedPassword, ok := "test", true
// 如果给定用户存在密码
// 并且,如果它与我们收到的密码相同,则可以继续
// 如果不是,则返回“未经授权”状态
if !ok || expectedPassword != creds.Password {
log.Println("bad password")
w.WriteHeader(http.StatusUnauthorized)
return
}
// 创建一个新的随机会话令牌
// 我们使用“github.com/google/uuid”库生成UUID
sessionToken := uuid.NewString()
expiresAt := time.Now().Add(120 * time.Second)
// 将令牌与会话信息一起设置在会话映射中
sessions[sessionToken] = session{
username: creds.Username,
expiry: expiresAt,
}
// 最后,我们将客户端cookie设置为“session_token”,值为刚生成的会话令牌
// 我们还设置了120秒的过期时间
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: sessionToken,
Expires: expiresAt,
})
log.Println("login success")
by, _ := json.Marshal(map[string]interface{}{
"to": "http://localhost:8085/users",
})
w.Write(by)
}
我使用了JSON响应而不是HTTP重定向。回到您的ajax调用,我再次将数据类型更改为JSON,因为我们的服务器现在发送JSON。将if条件从resp.redirect更改为resp.to,并使用window.location.href而不是windows.location.redirect。
function handleSubmit(evt) {
evt.preventDefault();
let form = evt.target;
let data = new FormData(form);
if (data.get("username") != null && data.get("username") != "") {
$.ajax({
url: 'http://localhost:8085/login',
method: 'post',
data: JSON.stringify(Object.fromEntries(data)),
dataType: 'json',
success: (resp) => {
if (resp.to) {
window.location.href = resp.to;
}
},
error: (resp) => {
console.log("An error occurred. Please try again");
console.log(resp)
}
});
}
return false
}
英文:
so to fix ur issue u should modify a little bit your server code
func login(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
log.Println("login started")
var creds Credentials
// Get the JSON body and decode into credentials
if err := json.NewDecoder(r.Body).Decode(&creds); err != nil {
// If the structure of the body is wrong, return an HTTP error
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
// Get the expected password from our in memory map
expectedPassword, ok := "test", true
// If a password exists for the given user
// AND, if it is the same as the password we received, then we can move ahead
// if NOT, then we return an "Unauthorized" status
if !ok || expectedPassword != creds.Password {
log.Println("bad password")
w.WriteHeader(http.StatusUnauthorized)
return
}
// Create a new random session token
// we use the "github.com/google/uuid" library to generate UUIDs
sessionToken := uuid.NewString()
expiresAt := time.Now().Add(120 * time.Second)
// Set the token in the session map, along with the session information
sessions[sessionToken] = session{
username: creds.Username,
expiry: expiresAt,
}
// Finally, we set the client cookie for "session_token" as the session token we just generated
// we also set an expiry time of 120 seconds
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: sessionToken,
Expires: expiresAt,
})
log.Println("login success")
by, _ := json.Marshal(map[string]interface{}{
"to": "http://localhost:8085/users",
})
w.Write(by)
}
i used json response instead of http.redirect.
Back to your ajax call, i change again the datatype to json because our server now send json. change the if condition from resp.redirect to resp.to, and use window.location.href instead of windows.location.redirect.
function handleSubmit(evt) {
evt.preventDefault();
let form = evt.target;
let data = new FormData(form);
if (data.get("username") != null && data.get("username") != "") {
$.ajax({
url: 'http://localhost:8085/login',
method: 'post',
data: JSON.stringify(Object.fromEntries(data)),
dataType: 'json',
success: (resp) => {
if (resp.to) {
window.location.href = resp.to;
}
},
error: (resp) => {
console.log("An error occurred. Please try again");
console.log(resp)
}
});
}
return false
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论