[深入分析]Required String parameter xxxx is not present

开门见山,直接展示问题如下:

还原场景

  • 报错信息
 WARN news [http-nio-8888-exec-1] [o.s.w.s.m.support.DefaultHandlerExceptionResolver:197] 
 Resolved [org.springframework.web.bind.MissingServletRequestParameterException: 
 Required String parameter 'sessionId' is not present]
  • 请求方式
    [深入分析]Required String parameter xxxx is not present_第1张图片
  • Controller层代码
@GetMapping(value = "/list")
    @ResponseBody
    Response> list(@RequestParam(value = "sessionId") String sessionId){
        String redisResult = jedisPool.getResource().get(sessionId);
        Response> r = new Response<>();
        if(MySessionCheckUtil.checkIsAdmin(redisResult)){
            r= r.setSuccessResult(BaseConstant.SUCCESS_MSG,crawlerManageService.listAll());
            return r;
        }else {
            r = r.setNoPerssionResult(BaseConstant.NO_PERMISSION,null);
            return r;
        }
}
  • 奇怪原因

本地测试正常,可以接收到sessionId参数,并成功返回。
在服务器上测试时,接收不到参数。

分析问题

  • 请求方式不对么?

@GetMapping(value = “/list”) 和@RequestMapping(value=“list”, method=RequestMethod.GET)是一样的效果

  • 难道Headers里面的ContentType需要设置为Content-Type:application/x-www-form-urlencoded

进过查阅资料整理如下:

@RequestParam用于将请求参数区数据映射到功能处理方法的参数上

Response list(@RequestParam(value = “sessionId”) String sessionId)

对于这样的请求方式:http:domain/api/v1.0/crawler/list?sessionId=xxxxx ,请求中包含sessionId(如/requestparam1?userName=xxxx),则会自动传入至sessionId参数中,后端即可获取到该值。
如果前端不传入这个参数,则会报:Required String parameter sessionId is not present,意思就是所需的字符串参数sessionid不存在。
实际上在postman已经传入了。

  1. 设置headers里Content-Type:application/x-www-form-urlencoded

此种方法依然没有解决问题。其实从本地测试没问题,服务器测试有问题本身可以判断出来问题大概出现在服务器端。
本着对application/x-www-form-urlencoded格式的学习态度,又了解了下请求方式的问题。
@RequestParam可以接收get和post请求的方式的参数,但需要设置content-type为:application/x-www-form-urlencoded。postman 默认content-type为application/x-www-form-urlencoded。@RequestParam是处理简单、平面的key-value键值对,如name=hk&sex=0,application/json是处理复杂的数据,多次结构也可以处理,采用@RequestBody注解。

  • 验证是否服务端问题

由于我刚用的域名去请求接口,服务端nginx做了反向代理,代理设置如下:

location  ~ /api/v1.0/(.*){
                proxy_set_header           Host $http_host;
                proxy_set_header           X-Real-IP $remote_addr;
                proxy_set_header           X-Forwarded-For $proxy_add_x_forwarded_for;
               proxy_pass http://127.0.0.1:6666/api/v1.0/$1;
}

尝试采用 http://damain:6666/api/v1.0/crawler/list 接口去请求,结果正常返回。
问题已经很明显了,是我的location 规章没有将参数传到后端,因而后端接收不到请求参数而报错。

  • 验证是否确实没有将参数传过去
location ~/api/v2.0/(.*){
                proxy_pass http://127.0.0.1/api/v3.0/$1;
        }

        location ~/api/v3.0/{
                allow all;
        }

采用curl http://www.domain.cn/api/v2.0/crawler/list?sessionId=xxxx

//结果
2019/04/28 19:46:14 [error] 7636#0: *1018 open() "/usr/local/nginx/html/api/v3.0/crawler/list" 
failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: 
"GET /api/v3.0/crawler/list HTTP/1.0", host: "127.0.0.1"

解决问题

  • 换了一个种匹配规则
location  /api/v1.0/{
                proxy_set_header           Host $http_host;
                proxy_set_header           X-Real-IP $remote_addr;
                proxy_set_header           X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://127.0.0.1:6666/api/v1.0/;
}

服务器端能够正常接收到@RequestParam注解定义的参数了。

参考资料

[^1 ]@RequestParam详解
[^2 ]application/json和application/x-www-form-urlencoded使用选择

你可能感兴趣的:(Spring,Boot)