Home > Blockchain >  Probleme with httptest postForm in golang
Probleme with httptest postForm in golang

Time:01-22

i receive a response body "bad request" with "httptest.Client().Postform"

type testServer struct {
    *httptest.Server
}

func newTestServer(t *testing.T, h http.Handler) *testServer {
    ts := httptest.NewTLSServer(h)

    jar, err := cookiejar.New(nil)
    if err != nil {
        t.Fatal(err)
    }

    ts.Client().Jar = jar

    ts.Client().CheckRedirect = func(req *http.Request, via []*http.Request) error {
        return http.ErrUseLastResponse
    }
    return &testServer{ts}
}
func (ts *testServer) postForm(t *testing.T, urlPath string, form url.Values) (int, http.Header, string) {
    rs, err := ts.Client().PostForm(ts.URL urlPath, form)
    if err != nil {
        t.Fatal(err)
    }
    defer rs.Body.Close()
    body, err := io.ReadAll(rs.Body)

    if err != nil {
        t.Fatal(err)
    }
    bytes.TrimSpace(body)

    return rs.StatusCode, rs.Header, string(body)
}

I don't know where is the problem, i have also verified the url it's correct. Always badrequest with POST but with GET request it's works fine.

this is the handler object :

func (app *application) routes() http.Handler {
    router := httprouter.New()
router.NotFound = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        app.notFound(w)
    })
dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.Authenticated)
    router.Handler(http.MethodGet, "/", dynamic.ThenFunc(app.home))
    router.Handler(http.MethodGet, "/user/signup", dynamic.ThenFunc(app.userSignup))
    router.Handler(http.MethodPost, "/user/signup", dynamic.ThenFunc(app.userSignupPost))
    standart := alice.New(app.recoverPanic, app.logRequest, securityHeaders)

    return standart.Then(router)
}


the test function :https://go.dev/play/p/k45-JYTYCOS

the app.userSignupPost:

func (app *application) userSignupPost(w http.ResponseWriter, r *http.Request) {
    var form userSignupForm
    err := app.decodPostForm(r, &form)
    if err != nil {
        app.clientError(w, http.StatusBadRequest)
        return
    }

    form.CheckField(validator.NotBlank(form.Name), "name", "this field must not be blank")
    form.CheckField(validator.NotBlank(form.Email), "email", "this field must not be blank")
    form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "this field must be a valid email address")
    form.CheckField(validator.NotBlank(form.Password), "password", "this field must not be blank")
    form.CheckField(validator.MinChars(form.Password, 8), "password", "password must bee at least 8 caracter long")
    if !form.Valid() {
        data := app.newTemplateData(r)
        data.Form = form
        app.render(w, http.StatusUnprocessableEntity, "signup.tmpl.html", data)
        return
    }
    err = app.users.Insert(form.Name, form.Email, form.Password)
    if err != nil {
        if errors.Is(err, models.ErrDuplicateEmail) {
            form.AddFieldError("email", "Email already exist")

            data := app.newTemplateData(r)
            data.Form = form
            app.render(w, http.StatusUnprocessableEntity, "signup.tmpl.html", data)
        } else {
            fmt.Println("error user postform")
            app.serverError(w, err)
        }
        return
    }
    app.sessionManager.Put(r.Context(), "flash", "Signup Successful. Please log in")
    http.Redirect(w, r, "/user/login", http.StatusSeeOther)
}

CodePudding user response:

It appears that you're using https://github.com/justinas/alice to register handlers - you don't want to do this. That package is for middleware chaining - e.g. "before all requests to this URL, first authenticate the request" - you'd put the authentication into a middleware function and then add it to the chain.

So every POST /user/signup request is getting passed first to app.userSignup() (what you are using to handle GET requests). This is because calling alice.ThenFunc() appends the passed handler to the chain and then returns the entire chain as a handler - you need to read this part of the Alice docs carefully before using it.

Replace this line:

router.Handler(http.MethodPost, "/user/signup", dynamic.ThenFunc(app.userSignupPost))

with

router.Handler(http.MethodPost, "/user/signup", http.HandlerFunc(app.userSignupPost))

You may not need the additional decoration of http.HandlerFunc() - try it with and without to see what works. I cannot say for sure without knowing what the body of app.userSignupPost() looks like (same for the other handler functions as well).

You'll then need to do the same for the other handler registration lines - you shouldn't be using middleware chaining for your end handlers. An http.Handler is used for saying, "send any request to path /PP/ppp with method XXXX to this function." Middleware chaining is for preprocessing (authentication, authorization, etc.) - a whole host of things can be done there, but end request handling shouldn't be one of them.

I'm still curious if your use of PostForm() is going to cause you issues for the reason I cited in my comment on your question - try a raw Post() and see if the behavior differs, but after refactoring to take out the alice goop (at least temporarily). When testing a handler, I'd start off with a much more minimal approach - test that the handler itself works before muddying the waters with both alice and what looks like this package.

CodePudding user response:

I think i found the problem , the session cookie are not the same for get and post request. i don't know why it has changed.They use the same http.Client()

  •  Tags:  
  • go
  • Related