POST 参数为空,但存在于 body

POST parameter null, but present in body

我有一个在本地运行良好的应用程序,但在客户端上它崩溃了,因为 POST 参数为空。

((HttpServletRequest)request).getParameter("dtid");

这个return空的。

所以我添加了一个过滤器来记录请求的 GET/POST/BODY。 在本地,日志如下所示:

[METHOD:POST] [REQUEST URI:/peps/zkau] [REQUEST PARAMETERS:{dtid=z_0n8, uuid_0=x38Pz, data_0={"pageX":372,"pageY":103,"which":1,"x":40.79998779296875,"y":4}, cmd_0=onClick}] [REQUEST BODY:] [REMOTE ADDRESS:0:0:0:0:0:0:0:1]

我在请求参数中有 dtid,body 是空的。 在客户端上,相同的日志如下所示:

[METHOD:POST] [REQUEST URI:/peps/zkau] [REQUEST PARAMETERS:{}] [REQUESTBODY:dtid=z_cb50&cmd_0=onOpen&uuid_0=l2sT30&data_0=%7B%22open%22%3Atrue%2C%22reference%22%3A%22l2sT20%22%7D&cmd_1=onClick&uuid_1=l2sT40&data_1=%7B%22pageX%22%3A323%2C%22pageY%22%3A138%2C%22which%22%3A1%2C%22x%22%3A323%2C%22y%22%3A138%7D&cmd_2=onOpen&uuid_2=l2sT30&data_2=%7B%22open%22%3Afalse%7D] [REMOTE ADDRESS:x.x.x.x]

参数为空图,但body已满。 body 似乎未被处理是什么原因造成的?为什么 body 没有被解析并注入到参数映射中?

谢谢

这是我的过滤器:

public class PepsParamFilter implements Filter {

    private static final Logger LOG = Logger.getLogger(PepsParamFilter.class.getName());

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;

            Map<String, String> requestMap = this.getTypesafeRequestMap(httpServletRequest);
            BufferedRequestWrapper bufferedReqest = new BufferedRequestWrapper(httpServletRequest);            

            chain.doFilter(bufferedReqest, response);

             //Request
                final StringBuilder reqMessage = new StringBuilder("").append("[METHOD:")
                        .append(httpServletRequest.getMethod())                        
                        .append("] [REQUEST URI:")
                        .append(httpServletRequest.getRequestURI())                        
                        .append("] [REQUEST PARAMETERS:").append(requestMap)
                        .append("] [REQUEST BODY:")
                        .append(bufferedReqest.getRequestBody())
                        .append("] [REMOTE ADDRESS:")
                        .append(httpServletRequest.getRemoteAddr()).append("]");
                if(!httpServletRequest.getRequestURI().endsWith(".gif")
                    && !httpServletRequest.getRequestURI().endsWith(".png")
                    && !httpServletRequest.getRequestURI().endsWith(".css")
                    ) {
                    LOG.info(reqMessage);
                }



        } catch (Throwable a) {
            LOG.error(a.getMessage(),a);
        }
    }

    private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
        Map<String, String> typesafeRequestMap = new HashMap<String, String>();
        Enumeration<?> requestParamNames = request.getParameterNames();
        while (requestParamNames.hasMoreElements()) {
            String requestParamName = (String) requestParamNames.nextElement();
            String requestParamValue = request.getParameter(requestParamName);
            typesafeRequestMap.put(requestParamName, requestParamValue);
        }
        return typesafeRequestMap;
    }

    @Override
    public void destroy() {
    }

    private static final class BufferedRequestWrapper extends
            HttpServletRequestWrapper {

        private ByteArrayInputStream bais = null;
        private ByteArrayOutputStream baos = null;
        private BufferedServletInputStream bsis = null;
        private byte[] buffer = null;

        public BufferedRequestWrapper(HttpServletRequest req)
                throws IOException {
            super(req);
            // Read InputStream and store its content in a buffer.
            InputStream is = req.getInputStream();
            this.baos = new ByteArrayOutputStream();
            byte buf[] = new byte[1024];
            int letti;
            while ((letti = is.read(buf)) > 0) {
                this.baos.write(buf, 0, letti);
            }
            this.buffer = this.baos.toByteArray();
        }

        @Override
        public ServletInputStream getInputStream() {
            this.bais = new ByteArrayInputStream(this.buffer);
            this.bsis = new BufferedServletInputStream(this.bais);

            return this.bsis;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }

        String getRequestBody() throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    this.getInputStream()));
            String line = null;
            StringBuilder inputBuffer = new StringBuilder();
            do {
                line = reader.readLine();
                if (null != line) {
                    inputBuffer.append(line.trim());
                }
            } while (line != null);
            reader.close();
            return inputBuffer.toString().trim();
        }

    }

    private static final class BufferedServletInputStream extends
            ServletInputStream {

        private ByteArrayInputStream bais;

        public BufferedServletInputStream(ByteArrayInputStream bais) {
            this.bais = bais;
        }

        @Override
        public int available() {
            return this.bais.available();
        }

        @Override
        public int read() {
            return this.bais.read();
        }

        @Override
        public int read(byte[] buf, int off, int len) {
            return this.bais.read(buf, off, len);
        }

    }

    public class TeeServletOutputStream extends ServletOutputStream {

        private final TeeOutputStream targetStream;

        public TeeServletOutputStream(OutputStream one, OutputStream two) {
            targetStream = new TeeOutputStream(one, two);
        }

        @Override
        public void write(int arg0) throws IOException {
            this.targetStream.write(arg0);
        }

        public void flush() throws IOException {
            super.flush();
            this.targetStream.flush();
        }

        public void close() throws IOException {
            super.close();
            this.targetStream.close();
        }
    }


}

通过 POST 调用,参数将在请求正文中发送,这发生在您服务器的日志中。因此,您需要获取请求正文才能访问所需的参数,请参阅此 question 如何获取 post 数据。

3.1.1 of the Servlet-spec 节指出:

3.1.1 When Parameters Are Available

The following are the conditions that must be met before post form data will be populated to the parameter set:

  1. The request is an HTTP or HTTPS request.
  2. The HTTP method is POST.
  3. The content type is application/x-www-form-urlencoded.
  4. The servlet has made an initial call of any of the getParameter family of methods on the request object.

If the conditions are not met and the post form data is not included in the parameter set, the post data must still be available to the servlet via the request object’s input stream. If the conditions are met, post form data will no longer be available for reading directly from the request object’s input stream.

您必须检查这些条件是否适用于您的本地或客户端系统。

可能有其他过滤器(在您之前的过滤器链中)已经处理了请求 body,或者更改了内容类型,或者之前访问过其中一种 getParameter* 方法,或者包装了请求...(你明白了)

本质上,这两种状态都有效,具体取决于您之前的请求发生了什么。

首先要检查的是浏览器是否发送相同的请求(/body)和headers。例如。在浏览器的开发者工具中。如果它们相同,请检查您的 web.xml 是否有其他过滤器(例如,本地开发环境和生产环境之间的安全过滤器通常不同)。