美文网首页
springboot 打印日志时碰到的问题

springboot 打印日志时碰到的问题

作者: 躺着真的舒服 | 来源:发表于2020-09-08 18:02 被阅读0次

在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<MultipartFile> 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解析,有知道的小伙伴请留言告诉我一下,不胜感激。

相关文章

网友评论

      本文标题:springboot 打印日志时碰到的问题

      本文链接:https://www.haomeiwen.com/subject/lhzdektx.html