Golang 发送的 POST 请求返回 400 错误请求。

huangapple go评论76阅读模式
英文:

Golang Post 400 bad request

问题

我正在尝试进行简单的登录操作。我按照Udemy上的教程进行操作,其中介绍了使用render函数来渲染模板。但我决定以不同的方式处理模板,不使用render函数,并对所有内容进行了更改。但我没有修改PostLoginHandler函数。自从我进行了这些更改后,我的"/login"的POST请求就停止工作了,我得到了"400 bad request"的错误,但我无法找出原因。我将包含我认为重要的代码。我认为问题可能与请求本身有关,以及教程中添加的CSRF令牌,由于更改后我没有使用它。我没有使用template.Must(template.ParseGlob("./templates/*.tmpl"))来处理模板。

另外,对于这篇长文,我很抱歉,我不确定需要哪些信息。提前感谢您的任何回复。

旧的render函数。

func RenderTemplate(w http.ResponseWriter, r *http.Request, t string, pd *models.PageData) {
	var tmpl *template.Template
	var err error
	_, inMap := tmplCache[t]
	if !inMap {
		err = makeTemplateCache(t)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println("Template in cache")
		}
	}
	tmpl = tmplCache[t]

	pd = AddCSRFData(pd, r)

	err = tmpl.Execute(w, pd)
	if err != nil {
		fmt.Println(err)
	}
}

路由部分

mux := chi.NewRouter()
mux.Use(middleware.Recoverer)
mux.Use(NoSurf)
mux.Use(SetupSession)

mux.Post("/login", handlers.Repo.PostLoginHandler)

甚至没有进入PostLoginHandler函数,但代码如下:

func (m *Repository) PostLoginHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("here")

	//strMap := make(map[string]string)
	_ = m.App.Session.RenewToken(r.Context())
	err := r.ParseForm()
	if err != nil {
		log.Fatal(err)
	}
	email := r.Form.Get("email")
	password := r.Form.Get("password")

	form := forms.New(r.PostForm)
	form.HasRequired("email", "password")
	form.IsEmail("email")

	if !form.Valid() {
		err := m.App.UITemplates.ExecuteTemplate(w, "login.page.tmpl", &models.PageData{Form: form})
		if err != nil {
			return
		}
		//render.RenderTemplate(w, r, "login.page.tmpl", &models.PageData{Form: form})
		return
	}
	id, _, err := m.DB.AuthenticateUser(email, password)
	if err != nil {
		m.App.Session.Put(r.Context(), "error", "Invalid Email OR Password")
		http.Redirect(w, r, "/login", http.StatusSeeOther)
		return
	}
	m.App.Session.Put(r.Context(), "user_id", id)
	m.App.Session.Put(r.Context(), "flash", "Valid Login")
	http.Redirect(w, r, "/", http.StatusSeeOther)
	//render.RenderTemplate(w, r, "page.page.tmpl", &models.PageData{StrMap: strMap})
}

最后,HTML是一个简单的表单:

<form method="post" action="/login">

   {{/*<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">*/}}

   <h1 class="h3 mb-3 fw-normal">Please sign in</h1>
   <div class="form-floating">
       <input type="email" class="form-control" id="email" name="email" placeholder="name@example.com">
       <label for="email">Email address</label>
   </div>
   <div class="form-floating">
       <input type="password" class="form-control" id="password" name="password" placeholder="Password">
       <label for="password">Password</label>
   </div>
   <div class="checkbox mb-3">
       <label>
           <input type="checkbox" value="remember-me"> Remember me
       </label>
   </div>
   <button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
</form>
英文:

I am trying to do a simple login. I followed a tutorial on Udemy. It went through rendering templates with a render function. I decided I wanted to handle templates differently and not have a render function and changed everything around. But I did not touch the PostLoginHandler. Since I made this change my post for "/login" has stopped working. I get "400 bad request" and I can't figure out why. I'll include the code that I think is important. I will say that I think it has something to do with the request, and/or CRSF token the tutorial added that I have not used since the changes. I am not using template.Must(template.ParseGlob("./templates/*.tmpl")) for handling templates.

Also, I'm sorry about the long post, I wasn't sure what info would be needed. Thank you in advance for any responses.

Old render function.

func RenderTemplate(w http.ResponseWriter, r *http.Request, t string, pd *models.PageData) {
	var tmpl *template.Template
	var err error
	_, inMap := tmplCache[t]
	if !inMap {
		err = makeTemplateCache(t)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(&quot;Template in cache&quot;)
		}
	}
	tmpl = tmplCache[t]

	pd = AddCSRFData(pd, r)

	err = tmpl.Execute(w, pd)
	if err != nil {
		fmt.Println(err)
	}
}

routes

mux := chi.NewRouter()
mux.Use(middleware.Recoverer)
mux.Use(NoSurf)
mux.Use(SetupSession)

mux.Post(&quot;/login&quot;, handlers.Repo.PostLoginHandler)

It's not even getting to the PostLoginHandler, but the code is

func (m *Repository) PostLoginHandler(w http.ResponseWriter, r *http.Request) {
	log.Println(&quot;here&quot;)

	//strMap := make(map[string]string)
	_ = m.App.Session.RenewToken(r.Context())
	err := r.ParseForm()
	if err != nil {
		log.Fatal(err)
	}
	email := r.Form.Get(&quot;email&quot;)
	password := r.Form.Get(&quot;password&quot;)

	form := forms.New(r.PostForm)
	form.HasRequired(&quot;email&quot;, &quot;password&quot;)
	form.IsEmail(&quot;email&quot;)

	if !form.Valid() {
		err := m.App.UITemplates.ExecuteTemplate(w, &quot;login.page.tmpl&quot;, &amp;models.PageData{Form: form})
		if err != nil {
			return
		}
		//render.RenderTemplate(w, r, &quot;login.page.tmpl&quot;, &amp;models.PageData{Form: form})
		return
	}
	id, _, err := m.DB.AuthenticateUser(email, password)
	if err != nil {
		m.App.Session.Put(r.Context(), &quot;error&quot;, &quot;Invalid Email OR Password&quot;)
		http.Redirect(w, r, &quot;/login&quot;, http.StatusSeeOther)
		return
	}
	m.App.Session.Put(r.Context(), &quot;user_id&quot;, id)
	m.App.Session.Put(r.Context(), &quot;flash&quot;, &quot;Valid Login&quot;)
	http.Redirect(w, r, &quot;/&quot;, http.StatusSeeOther)
	//render.RenderTemplate(w, r, &quot;page.page.tmpl&quot;, &amp;models.PageData{StrMap: strMap})
}

and lastly, the HTML is a simple form

&lt;form method=&quot;post&quot; action=&quot;/login&quot;&gt;

   {{/*&lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{.CSRFToken}}&quot;&gt;*/}}

   &lt;h1 class=&quot;h3 mb-3 fw-normal&quot;&gt;Please sign in&lt;/h1&gt;
   &lt;div class=&quot;form-floating&quot;&gt;
       &lt;input type=&quot;email&quot; class=&quot;form-control&quot; id=&quot;email&quot; name=&quot;email&quot; placeholder=&quot;name@example.com&quot;&gt;
       &lt;label for=&quot;email&quot;&gt;Email address&lt;/label&gt;
   &lt;/div&gt;
   &lt;div class=&quot;form-floating&quot;&gt;
       &lt;input type=&quot;password&quot; class=&quot;form-control&quot; id=&quot;password&quot; name=&quot;password&quot; placeholder=&quot;Password&quot;&gt;
       &lt;label for=&quot;password&quot;&gt;Password&lt;/label&gt;
   &lt;/div&gt;
   &lt;div class=&quot;checkbox mb-3&quot;&gt;
       &lt;label&gt;
           &lt;input type=&quot;checkbox&quot; value=&quot;remember-me&quot;&gt; Remember me
       &lt;/label&gt;
   &lt;/div&gt;
   &lt;button class=&quot;w-100 btn btn-lg btn-primary&quot; type=&quot;submit&quot;&gt;Sign in&lt;/button&gt;
&lt;/form&gt;

答案1

得分: 1

400 bad request 是使用 Nosurf 中间件时出现的错误。

首先,你需要在模板中取消注释这一行,因为这是用于 CSRF 验证的必需项。

<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">

其次,你需要确保 CSRFToken 正确地传递到模板中。我希望这是在 AddCSRFData 函数中更新的。

我得到了 "400 bad request" 的错误,但我无法弄清楚原因。

默认情况下,当发生错误时,该包不会记录任何内容。但是可以重写 "failure handler" 来查看导致 "400 bad request" 的确切原因。

请参考以下示例代码:

package main

import (
	"fmt"
	"html/template"
	"net/http"

	"github.com/go-chi/chi"
	"github.com/go-chi/chi/middleware"
	"github.com/justinas/nosurf"
)

var formTemplate = `
	<html>
	<body>

		<form method="post" action="/submit">
			<!--  comment this and see error -->
			<input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">

			<h1 class="h3 mb-3 fw-normal">Please sign in</h1>
			<div class="form-floating">
				<input type="email" class="form-control" id="email" name="email" placeholder="name@example.com">
				<label for="email">Email address</label>
			</div>
			<div class="form-floating">
				<input type="password" class="form-control" id="password" name="password" placeholder="Password">
				<label for="password">Password</label>
			</div>
			<div class="checkbox mb-3">
				<label>
					<input type="checkbox" value="remember-me"> Remember me
				</label>
			</div>

			<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
		</form>
	</body>
	</html>
`
var tmpl = template.Must(template.New("t1").Parse(formTemplate))

// FailureFunction
// 重写默认的 nosurf failure Handler
func FailureFunction() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf("Request Failed. Reason: %v", nosurf.Reason(r))
		http.Error(w, http.StatusText(nosurf.FailureCode), nosurf.FailureCode)
	})
}

// NoSurf
// 设置处理程序并重写默认的 nosurf failure Handler
func NoSurf(handler http.Handler) http.Handler {
	obj := nosurf.New(handler)
	obj.SetFailureHandler(FailureFunction()) // 重写默认的 failure Handler
	return obj
}

func main() {
	r := chi.NewRouter()

	// 添加中间件
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)
	r.Use(NoSurf)

	r.Get("/", HomeHandler)
	r.Post("/submit", SubmitHandler)

	http.ListenAndServe(":8080", r)
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	token := nosurf.Token(r) // 生成令牌

	data := map[string]interface{}{
		"CSRFToken": token, // 注释掉这一行并查看错误
	}
	err := tmpl.Execute(w, data)
	if err != nil {
		http.Error(w, "unable to execute the template", http.StatusInternalServerError)
		return
	}
}

func SubmitHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	if !nosurf.VerifyToken(nosurf.Token(r), r.PostForm.Get("csrf_token")) {
		http.Error(w, "Invalid CSRF Token", http.StatusForbidden)
		return
	}

	w.Write([]byte("success"))
}

希望这能帮助你解决问题。

英文:

400 bad request is getting with Nosurf middleware.

Firstly, you should un-comment this in your template. As this is required for crsf validation.

&lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{.CSRFToken}}&quot;&gt;

Secondly, you should ensure that the CSRFToken correctly passed into the template. I hope this is updating within AddCSRFData function.

> I get "400 bad request" and I can't figure out why.

By default the package is not logging anything when an error happened. But it is possible to override the failure handler to see what exact reason caused the 400 bad request.

See the sample code

package main

import (
	&quot;fmt&quot;
	&quot;html/template&quot;
	&quot;net/http&quot;

	&quot;github.com/go-chi/chi&quot;
	&quot;github.com/go-chi/chi/middleware&quot;
	&quot;github.com/justinas/nosurf&quot;
)

var formTemplate = `
	&lt;html&gt;
	&lt;body&gt;

		&lt;form method=&quot;post&quot; action=&quot;/submit&quot;&gt;
			&lt;!--  comment this and see error --&gt;
			&lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{ .CSRFToken }}&quot;/&gt;

			&lt;h1 class=&quot;h3 mb-3 fw-normal&quot;&gt;Please sign in&lt;/h1&gt;
			&lt;div class=&quot;form-floating&quot;&gt;
				&lt;input type=&quot;email&quot; class=&quot;form-control&quot; id=&quot;email&quot; name=&quot;email&quot; placeholder=&quot;name@example.com&quot;&gt;
				&lt;label for=&quot;email&quot;&gt;Email address&lt;/label&gt;
			&lt;/div&gt;
			&lt;div class=&quot;form-floating&quot;&gt;
				&lt;input type=&quot;password&quot; class=&quot;form-control&quot; id=&quot;password&quot; name=&quot;password&quot; placeholder=&quot;Password&quot;&gt;
				&lt;label for=&quot;password&quot;&gt;Password&lt;/label&gt;
			&lt;/div&gt;
			&lt;div class=&quot;checkbox mb-3&quot;&gt;
				&lt;label&gt;
					&lt;input type=&quot;checkbox&quot; value=&quot;remember-me&quot;&gt; Remember me
				&lt;/label&gt;
			&lt;/div&gt;

			&lt;button class=&quot;w-100 btn btn-lg btn-primary&quot; type=&quot;submit&quot;&gt;Sign in&lt;/button&gt;
		&lt;/form&gt;
	&lt;/body&gt;
	&lt;/html&gt;
`
var tmpl = template.Must(template.New(&quot;t1&quot;).Parse(formTemplate))

// FailureFunction
// Overriding the default nosurf failure Handler
func FailureFunction() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf(&quot;Request Failed. Reason: %v&quot;, nosurf.Reason(r))
		http.Error(w, http.StatusText(nosurf.FailureCode), nosurf.FailureCode)
	})
}

// NoSurf
// Setting up the handler with overrriding default nosurf failure Handler
func NoSurf(handler http.Handler) http.Handler {
	obj := nosurf.New(handler)
	obj.SetFailureHandler(FailureFunction()) // Override default failure Handler
	return obj
}

func main() {
	r := chi.NewRouter()

	// Add middleware
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)
	r.Use(NoSurf)

	r.Get(&quot;/&quot;, HomeHandler)
	r.Post(&quot;/submit&quot;, SubmitHandler)

	http.ListenAndServe(&quot;:8080&quot;, r)
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
	token := nosurf.Token(r) // generating the token

	data := map[string]interface{}{
		&quot;CSRFToken&quot;: token, // comment this and see the error
	}
	err := tmpl.Execute(w, data)
	if err != nil {
		http.Error(w, &quot;unable to execute the template&quot;, http.StatusInternalServerError)
		return
	}
}

func SubmitHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		http.Error(w, &quot;Bad Request&quot;, http.StatusBadRequest)
		return
	}

	if !nosurf.VerifyToken(nosurf.Token(r), r.PostForm.Get(&quot;csrf_token&quot;)) {
		http.Error(w, &quot;Invalid CSRF Token&quot;, http.StatusForbidden)
		return
	}

	w.Write([]byte(&quot;success&quot;))
}

Hoping this will help you to resolve your problem.

huangapple
  • 本文由 发表于 2023年6月9日 12:28:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76437217.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定