springboot日志输出异常_springboot 打印日志时碰到的问题

在springboot 项目上传文件时出现了以下错误

Required request part 'file' is not present

我是通过在Filter中使用HttpServletRequestWrapper 的形式打印请求和返回日志的,经过排查发现,使用HttpServletRequestWrapper 打印请求参数时,发现当HttpServletRequest请求的Content-Type 为application/json时能够正常解析,但是当用表单提交的形式时,springboot 找不到表单提交的参数,返回参数缺失相关的异常。

根据源码查询发现,在RequestParamMethodArgumentResolver类中 resolveName方法 中调用了request.getParameterValues(name),结果返回为null

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {

HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);

if (servletRequest != null) {

Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);

if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {

return mpArg;

}

}

Object arg = null;

MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);

if (multipartRequest != null) {

List files = multipartRequest.getFiles(name);

if (!files.isEmpty()) {

arg = (files.size() == 1 ? files.get(0) : files);

}

}

if (arg == null) {

String[] paramValues = request.getParameterValues(name);

if (paramValues != null) {

arg = (paramValues.length == 1 ? paramValues[0] : paramValues);

}

}

return arg;

}

HTML中的form表单有一个关键属性 enctype=application/x-www-form-urlencoded 或multipart/form-data。

enctype=application/x- www-form-urlencoded是默认的编码方式,这种编码方式很简单,编码后的结果通常是field1=value2&field2=value2&… 的形式,如 name=aaaa&Submit=Submit。这种编码的具体规则可以在 rfc2231 里查到, 通常使用的表单也 是采用这种方式编码的,Servlet 的 API 提供了对这种 编码方式解码的支持,只需要调用 ServletRequest 类中的getParameter()方法就可 以得到用户表单中的字段和数据。

而我们知道 request.getParameter(),request.getInputStream(),request.getReader()这三种方法是有冲突的,因为流只能读取一次。所以在我们通过表单提交的数据找不到。

我们根据HttpServletRequest 的Content-Type类型进行判断HttpServletRequestWrapper 进行哪种处理。

更改后的 RequestWrapper如下

@Slf4j

public class RequestWrapper extends HttpServletRequestWrapper {

private byte[] body;

/**

* Constructs a request object wrapping the given request.

*

* @param request The request to wrap

* @throws IllegalArgumentException if the request is null

*/

public RequestWrapper(HttpServletRequest request) {

super(request);

try {

if(HttpMethod.POST.matches(request.getMethod())){

log.error(request.getContentType()+"---------------");

if(request.getContentType().contains("application/x-www-form-urlencoded")){

// 通过getParameter的形式解析

body= JacksonUtil.objectToJson(request.getParameterMap()).getBytes();

}else if(request.getContentType().contains("multipart/form-data")){

body="文件类型,不解析".getBytes();

}else {

body = IOUtils.toByteArray(request.getInputStream());

}

}else { // get 请求通过getParameterMap 的方式获取

body= JacksonUtil.objectToJson(request.getParameterMap()).getBytes();

}

} catch (IOException e) {

e.printStackTrace();

}

}

@Override

public ServletInputStream getInputStream() throws IOException {

return new SignWrapperInputStream(body);

}

@Override

public BufferedReader getReader() throws IOException {

return new BufferedReader(new InputStreamReader(getInputStream()));

}

public byte[] getBody() {

return body;

}

public void setBody(byte[] body) {

this.body = body;

}

private class SignWrapperInputStream extends ServletInputStream {

private ByteArrayInputStream buffer;

public SignWrapperInputStream(byte[] body) {

body = (body == null) ? new byte[0] : body;

this.buffer = new ByteArrayInputStream(body);

}

@Override

public int read() throws IOException {

return buffer.read();

}

@Override

public boolean isFinished() {

return buffer.available() == 0;

}

@Override

public boolean isReady() {

return true;

}

@Override

public void setReadListener(ReadListener listener) {

throw new RuntimeException("Not implemented");

}

}

}

这样就可以进行json、表单、还有文件相关的日志打印了。按照道理来说 multipart/form-data类型应该也是通过 request.getInputStream()或者request.getReader()获取的,不知道为什么也是不能通过HttpServletRequestWrapper解析,有知道的小伙伴请留言告诉我一下,不胜感激。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值