验证表单“发送的请求在语法上不正确”时出现错误 400

Posted

技术标签:

【中文标题】验证表单“发送的请求在语法上不正确”时出现错误 400【英文标题】:Error 400 valiting form "The request sent was syntactically incorrect" 【发布时间】:2014-09-27 08:35:11 【问题描述】:

我在尝试使用 Spring Boot 和 Thymeleaf 验证表单时遇到问题。 from 只需使用给定字段注册用户。我使用的是多部分表单,因为表单也会上传图片,但我已经尝试使用没有它的表单,但仍然是同样的问题。

顺便说一句,我知道这个问题很多,但没有一个答案能帮助我......

如果表单字段正确,则一切正常。但是如果我输入一个无效的字段,我会得到响应:

HTTP 状态 400 -

输入状态报告

消息

说明客户端发送的请求语法错误。

我只是想显示一个气泡来警告该字段。目前我在 html 输入标签中使用 "pattern" ,但用户可以将其从浏览器中删除。我可以使控制器中的进程检查无效并重定向到相同的清理页面,但这只是一个不舒服的解决方法。

<form class="styleweb" id="registrationform" th:action="@/site/new_user" method="post" enctype="multipart/form-data">
        <fieldset>

            <div class="styleweb">
                <label for="login">Login</label> <input id="login" type="text"
                    placeholder="Username" th:field="$user.login" />
                    <p th:if="$#fields.hasErrors('user.login')" th:errors="*user.login">Incorrect stuff</p>
            </div>

            <div class="styleweb">
                <label for="password">Password</label>
                    <input id="password"
                    type="password" placeholder="Password" th:field="$user.password"/>
            </div>

            <div class="pure-control-group">
                <label for="email">Email Address</label> <input id="email"
                    type="email" placeholder="Email Address" th:field="$user.email"/>
            </div>

            <div class="pure-control-group">
                <label for="foo">Profile pic</label> <input type="file" name="profilePic" id="imgInp"/>
                <img id="profilepic" src="#"  />
            </div>

            <div class="styleweb">
                <button type="submit" class="styleweb">Submit</button>
            </div>
        </fieldset>
    </form>

这是控制器:

@RequestMapping(value="new_user", method = RequestMethod.GET)
    public String addUserPage(Model model) 
        model.addAttribute("user", new User());

        return "site/user/add_user";
    

    @RequestMapping(value = "new_user", method = RequestMethod.POST)
    public String processAddUserWeb(@Valid @ModelAttribute(value = "user") User user,
            @ModelAttribute(value = "profilePic") MultipartFile profilePic,
            BindingResult result) throws LoginNotAvailableException 

        if (result.hasErrors()) 
            System.out.println("Form has errors");
            return "elovendo/user/add_user";
         
        else  
            System.out.println("Form is ok");

            byte[] profilePicBytes = null;
            if (!profilePic.isEmpty()) try 
                profilePicBytes = profilePic.getBytes();
             catch (IOException e) 
                System.out.println("Error converting to bytes image file");
            

            userService.addUser(user, profilePicBytes);

            return "site/user/registered_successful";
        
    

而用户类是:

public class User implements UserDetails 

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "userId")
    private Long userId;

    @NotNull(message="Login cannot be null")
    @Length(min = 2, max = 20, message="Invalid login lenght")
    @Pattern(regexp=Constant.loginPattern, message="Invalid login name")
    private String login;

    @Column(name = "password", length = 255)
    @Length(min = 8, max = 255)
    private String password;

    private String email;

    // constructor, getters and setters, ...


我也尝试使用Validator的实现:

public class FormValidator implements Validator 

    private Pattern pattern;
    private Matcher matcher;

    @Override
    public boolean supports(Class<?> clazz) 
        return User.class.equals(clazz);
    

    @Override
    public void validate(Object target, Errors errors) 

        User user = (User) target;

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "login", "required.login");

        // input string conatains numeric values only
        if (user != null) 
            pattern = Pattern.compile(Constant.loginPattern);
            matcher = pattern.matcher(user.getLogin());
            if (!matcher.matches()) 
                errors.rejectValue("login", "login.invalid");
            
        
    

并在控制器中使用它作为(首先没有 @Valid 注释,但有或没有它都会执行相同的[相同错误]):

@RequestMapping(value = "new_user", method = RequestMethod.POST)
    public String processAddUserWeb(@ModelAttribute(value = "user") User user,
            @ModelAttribute(value = "profilePic") MultipartFile profilePic,
            BindingResult result) throws LoginNotAvailableException 
    FormValidator formValidator = new FormValidator();
    formValidator.validate(user, result);

    if (result.hasErrors()) 
        System.out.println("Form has errors");
        return "elovendo/user/add_user";
    

但也没有用。如果不使用 th:if="$#fields.hasErrors('user.login')(...) 标签(这很愚蠢,但我只是在拼命寻找一个解决方案)返回:

org.springframework.beans.NotReadablePropertyException: 无效 bean 类 [java.lang.String] 的属性“登录”:Bean 属性 'login' 不可读或有一个无效的 getter 方法: getter 的返回类型是否与 setter 的参数类型匹配? (...).validator.FormValidator.validate(FormValidator.java:28)

在这里问这是在处理这个问题时松开所有头发之前的最后一站,希望有人可以帮助我。 谢谢!

编辑

这是我发送带有无效数据的表单帖子时的日志:

2014-08-06 14:42:01.717 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /site/new_user
2014-08-06 14:42:01.718 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sdfd.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]
2014-08-06 14:42:01.743 DEBUG 9759 --- .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]1,20$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.744 DEBUG 9759 --- .w.s.m.a.ResponseStatusExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]1,20$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.745 DEBUG 9759 --- .w.s.m.s.DefaultHandlerExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]1,20$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.745 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2014-08-06 14:42:01.746 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Successfully completed request
2014-08-06 14:42:01.748 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing POST request for [/error]
2014-08-06 14:42:01.749 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2014-08-06 14:42:01.749 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sfacut.rest.controller.MainController.errorPage()]
2014-08-06 14:42:01.751 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Rendering view [org.thymeleaf.spring4.view.ThymeleafView@503dc0cf] in DispatcherServlet with name 'dispatcherServlet'
2014-08-06 14:42:01.755 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Successfully completed request

这是包含有效数据的日志:

2014-08-06 14:54:25.703 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/site/new_user]
2014-08-06 14:54:25.703 DEBUG 10138 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /site/new_user
2014-08-06 14:54:25.705 DEBUG 10138 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sfacut.rest.web.UserWebController.addUserPage(org.springframework.ui.Model)]
2014-08-06 14:54:25.705 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/site/new_user] is: -1
2014-08-06 14:54:25.712 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Rendering view [org.thymeleaf.spring4.view.ThymeleafView@4b34f94d] in DispatcherServlet with name 'dispatcherServlet'
2014-08-06 14:54:25.722 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Successfully completed request

【问题讨论】:

您是否尝试将BindingResult 放在User user 之后(现在您在MultipartFile profilePic 之后有它)? @geoand 好的,现在我得到了预期的页面而不是错误页面,但我在表单字段中根本看不到任何错误消息。使用或不使用我的验证器的实现。 尝试在@ModelAttribute 前面添加@Valid 并告诉我会发生什么 对不起@geoand,你的第一反应是对的!这是我的错,因为我评论了

没关系,我找到了:Errors 或 BindingResult 参数必须遵循立即绑定的模型对象,因为方法签名可能有多个模型对象,Spring 将创建一个单独的模型对象它们每个的 BindingResult 实例,因此以下示例将不起作用 docs.spring.io/spring/docs/current/spring-framework-reference/… at 16.3.3
【参考方案1】:

BindingResult 和@ModelAttribute 的排序无效 我只是改变顺序,像一个魅力一样醒来......

@RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String addUser( @ModelAttribute("SpringWeb")@Valid User user,BindingResult binding, ModelMap model) 
    System.out.println(binding.toString());

    if (!binding.hasErrors()) 

        System.out.println("Has No Error");
        model.addAttribute("username", user.getUsername());
        model.addAttribute("password", user.getPassword());
        model.addAttribute("address", user.getAddress());
        model.addAttribute("receivePaper", user.isReceivePaper());
        model.addAttribute("favoriteFrameworks", user.getFavoriteFrameworks());
        model.addAttribute("gender", user.getGender());
        model.addAttribute("favoriteNumber", user.getFavoriteNumber());
        model.addAttribute("country", user.getCountry());

        return "users";

     else 
        System.out.println("Has  Error");

        return "error";
    


【讨论】:

【参考方案2】:

您需要将BindingResult 放在User user 之后,Spring 才能正确处理无效数据。

控制器方法因此看起来像:

public String processAddUserWeb(@ModelAttribute(value = "user") User user,
                                BindingResult result,
                                @ModelAttribute(value = "profilePic") MultipartFile profilePic)

【讨论】:

【参考方案3】:

你的大部分 &lt;input&gt; 元素

<input id="login" type="text" placeholder="Username" th:field="$user.login" />
<input id="password" type="password" placeholder="Password" th:field="$user.password"/>
<input id="email" type="email" placeholder="Email Address" th:field="$user.email"/>

没有name 属性。要作为提交的&lt;form&gt; 的一部分发送&lt;input&gt; 元素,name 属性是必需的。所以这些没有被发送,验证似乎失败了。

name 属性(可能与id 具有相同的值)添加到您的&lt;input&gt; 元素。

【讨论】:

感谢您的回复,但添加名称属性完全没有区别。我尝试了添加属性的几件事,但似乎没有任何效果。 @frostering 您在发送有效数据吗?将您的日志转换为 DEBUG 级别,并准确地向我们展示针对错误请求和良好请求打印的内容。 当我发送有效数据并且一切正常时。但如果数据无效,则不会。我已经使用 HTML5 模式属性做了一个工作区,如果 Html5 表单已被编辑(所以我不允许无效值),我会抛出一个错误页面,但我想知道这不起作用以及为什么不起作用。我猜 Null ModelAndView 以名称“dispatcherServlet”返回到 DispatcherServlet:假设 HandlerAdapter 完成的请求处理与此有关?

以上是关于验证表单“发送的请求在语法上不正确”时出现错误 400的主要内容,如果未能解决你的问题,请参考以下文章

发送 post 请求时,客户端发送的请求在语法上不正确

客户端发送的请求在语法上不正确 Java ZonedDateTime 后端

提交表单时出现tinyMCE错误

在 ajax 调用 Mvc-4 应用程序中实现验证时出现错误

尝试通过 AJAX 验证 Laravel 表单时出现错误 422

表单验证失败时出现 502 Bad Gateway 错误