简体   繁体   English

POST 参数 null,但存在于正文中

[英]POST parameter null, but present in body

I have an application that works fine in local, but on the client it crashs because a POST parameter is null.我有一个在本地运行良好的应用程序,但在客户端它崩溃了,因为 POST 参数是 null。

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

This return null.这返回 null。

So I have added a filter to log GET/POST/BODY of the request.所以我添加了一个过滤器来记录请求的 GET/POST/BODY。 In local the log look like this:在本地,日志如下所示:

[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] [方法:POST] [请求 URI:/peps/zkau] [请求参数:{dtid =z_0n8, uuid_0=x38Pz, data_0={"pageX":372,"pageY":103,"which":1,"x ":40.79998779296875,"y":4}, cmd_0=onClick}] [请求正文:] [远程地址:0:0:0:0:0:0:0:1]

I have dtid in request param and the body is empty.我在请求参数中有 dtid 并且正文是空的。 On the client the same log looks like this:在客户端,相同的日志如下所示:

[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:xxxx] [方法:POST] [请求 URI:/peps/zkau] [请求参数:{} ] [请求体: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] [远程地址:xxxx]

Parameters is an empty map, but the body is full.参数是一个空的map,但是body是满的。 The body appears to be un processed what can cause this?身体似乎没有经过处理,这可能是什么原因? Why isn't the body parsed and inject in the parameter map?为什么body没有解析并注入参数map?

Thanks谢谢

Here is my Filter:这是我的过滤器:

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();
        }
    }


}

Section 3.1.1 of the Servlet-spec states: Servlet-spec 的第 3.1.1节指出:

3.1.1 When Parameters Are Available 3.1.1 参数可用时

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.请求是 HTTP 或 HTTPS 请求。
  2. The HTTP method is POST. HTTP 方法是 POST。
  3. The content type is application/x-www-form-urlencoded.内容类型为 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. servlet 已对请求 object 的任何 getParameter 系列方法进行了初始调用。

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.如果不满足条件且 post 表单数据未包含在参数集中,则 post 数据必须仍可通过请求对象的输入 stream 提供给 servlet。 If the conditions are met, post form data will no longer be available for reading directly from the request object's input stream.如果满足条件,则无法再从请求对象的输入 stream 直接读取发布表单数据。

You have to check if any of these conditions apply differently to your local or client system.您必须检查这些条件中的任何一个是否适用于您的本地或客户端系统。

There might be other filters (in the filter chain before yours), which already process the request body, or change the content type, or previously accessed one of the getParameter* methods, or wrapped the request... (you get the point)可能还有其他过滤器(在您之前的过滤器链中),它们已经处理了请求正文,或者更改了内容类型,或者之前访问了 getParameter* 方法之一,或者包装了请求......(你明白了)

In essence, both states are valid depending on what happened to your request earlier.本质上,这两种状态都是有效的,具体取决于您之前的请求发生了什么。

The first thing to check would be whether or not the browser sends the same request(/body) and headers.首先要检查的是浏览器是否发送相同的请求(/正文)和标头。 Eg in the browser's developer tools.例如在浏览器的开发者工具中。 If those are identical, check your web.xml for additional filters (eg security filters are often different between local dev and production environments).如果它们相同,请检查您的 web.xml 以获取其他过滤器(例如,本地开发环境和生产环境之间的安全过滤器通常不同)。

With a POST call, parameters will be sent in request body which is happening in the logs from your server.通过 POST 调用,参数将在请求正文中发送,这发生在您服务器的日志中。 So you will need to get request body to access the parameters you need, refer this question on how to get post data.因此,您需要获取请求正文才能访问所需的参数,请参阅this question on how to get post data。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM