当前位置: 首页 > 知识库问答 >
问题:

Java spring获取post请求的主体

申屠恺
2023-03-14

我有以下问题:我试图在Spring控制器处理POST请求之前获取它的主体。为此,我使用HandlerInterceptorAdapter的preHandle()方法。

如本讨论中所述 SpringREST服务:从请求中检索JSON 我也使用使用此包装器,我设法打印了第一个POST请求的正文,但第二个POST抛出一个IOException:流关闭。

您对如何获取所有POST请求的正文有什么想法吗?

下面是拦截器的preHandle()方法:

@Override
public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler) throws Exception {
    System.out.println(request.getMethod());
    MyRequestWrapper w = new MyRequestWrapper(request);

    BufferedReader r = w.getReader();
    System.out.println(r.readLine());

    return super.preHandle(request, response, handler);
}

HttpServletRequestWrapper:

public class MyRequestWrapper extends HttpServletRequestWrapper {
private ByteArrayOutputStream cachedBytes;
private HttpServletRequest request;

public MyRequestWrapper(HttpServletRequest request) {
    super(request);
    this.request = request;
}

@Override
public ServletInputStream getInputStream() throws IOException {
    cachedBytes = new ByteArrayOutputStream();

    if (request.getMethod().equals("POST"))
        cacheInputStream();

    return new CachedServletInputStream();
}

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

private void cacheInputStream() throws IOException {
    /*
     * Cache the inputstream in order to read it multiple times. For
     * convenience, I use apache.commons IOUtils
     */
    ServletInputStream inputStream = super.getInputStream();

    if (inputStream == null) {
        return;
    }

    IOUtils.copy(inputStream, cachedBytes);
}

/* An inputstream which reads the cached request body */
public class CachedServletInputStream extends ServletInputStream {
    private ByteArrayInputStream input;

    public CachedServletInputStream() {
        /* create a new input stream from the cached request body */
        input = new ByteArrayInputStream(cachedBytes.toByteArray());
    }

    @Override
    public int read() throws IOException {
        return input.read();
    }
}
}

控制台输出:

2014-10-15 12:13:00 INFO [http-nio-8080-exec-1] org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'dispatcherServlet': initialization completed in 9 ms
GET
null
GET
null
POST
{"long":null,"owner":{"__type":"Owner","id":20,"version":1,"md5Password":""},"string":"ws","tool":{"__type":"Tool","id":33,"version":1}}
POST
2014-10-15 12:13:00 ERROR [http-nio-8080-exec-3] org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet dispatcherServlet threw exception
java.io.IOException: Stream closed

共有2个答案

车子平
2023-03-14

我使用了实现过滤器的过滤器

过滤器。在这里,我包装了一个请求和一个响应,以便不仅从它们中读取一次。您可以为此使用ContentCachingRequest estWrapper和ContentCachingReportseWrapper。

    @Component
    public class RequestLogFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(RequestLogFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        logger.info("======================> FILTER <======================");

        HttpServletRequest requestToCache = new ContentCachingRequestWrapper((HttpServletRequest) request);
        HttpServletResponse responseToCache = new ContentCachingResponseWrapper((HttpServletResponse) response);

        // before method
        chain.doFilter(requestToCache, responseToCache);
        // after method

        // your logic(save to DB, logging...)
        getRequestData(request);
        getResponseData(response);
    }

    @Override
    public void destroy() {

    }

}

-

@Component
public class RequestLogInterceptor extends HandlerInterceptorAdapter {

    private final Logger logger = LoggerFactory.getLogger(RequestLogInterceptor.class);

    @Autowired
    private InboundRequestLogStore inboundRequestLogStore;

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {

        logger.info("====================> INTERCEPTOR <========================");

        try {
            if (request.getAttribute(InboundRequestAspect.INBOUND_LOG_MARKER) != null) {

                InboundRequestLogRecord logRecord = new InboundRequestLogRecord();

                logRecord.setIpAddress(request.getRemoteAddr());

                // getting request and response body
                logRecord.setRequestBody(getRequestData(request));
                logRecord.setResponseBody(getResponseData(response));

                logRecord.setResponseCode(((HttpServletResponse) response).getStatus());

                String uri = request.getScheme() + "://" + request.getServerName()
                        + ("http".equals(request.getScheme()) && request.getServerPort() == 80
                                || "https".equals(request.getScheme()) && request.getServerPort() == 443 ? ""
                                        : ":" + request.getServerPort())
                        + request.getRequestURI()
                        + (request.getQueryString() != null ? "?" + request.getQueryString() : "");
                logRecord.setUrl(uri);
                inboundRequestLogStore.add(logRecord);  // save to DB

              } else {

                        ((ContentCachingResponseWrapper) response).copyBodyToResponse(); // in other case you send null to the response

              }


        } catch (Exception e) {
            logger.error("error ", e);

            try {
                    ((ContentCachingResponseWrapper) response).copyBodyToResponse(); // in other case you send null to the response
                } catch (Exception e2) {
                    // TODO Auto-generated catch block
                    logger.error("error ", e2);
                }

        }



    }

    public static String getRequestData(final HttpServletRequest request) throws UnsupportedEncodingException {
        String payload = null;
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > 0) {
                payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
            }
        }
        return payload;
    }

        public static String getResponseData(final HttpServletResponse response) throws UnsupportedEncodingException, IOException {
            String payload = null;
            ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
            if (wrapper != null) {
                byte[] buf = wrapper.getContentAsByteArray();
                if (buf.length > 0) {
                    payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
                }
                wrapper.copyBodyToResponse();   // in other case you send null to the response
            }
            return payload;
        }

    }

添加到servlet-context.xml

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <beans:bean class="path.to.RequestLogInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

命名空间:

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

内容缓存请求Wrapper - http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/ContentCachingRequestWrapper.html

ContentCachingReportseWrapper-http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/ContentCachingResponseWrapper.html

厍胤运
2023-03-14

您试图从包装器中的原始请求中读取,但是在这之后,原始请求仍然被读取——因此请求输入流已经被消耗,不能再次被读取。

与其使用拦截器,不如考虑使用 javax.servlet.过滤器。在 doFilter 方法中,可以将包装的请求传递到链下游。

 类似资料:
  • 原理 对于POST请求的处理,koa2没有封装获取参数的方法,需要通过解析上下文context中的原生node.js请求对象req,将POST表单数据解析成query string(例如:a=1&b=2&c=3),再将query string 解析成JSON格式(例如:{"a":"1", "b":"2", "c":"3"}) 注意:ctx.request是context经过封装的请求对象,ctx.

  • 问题内容: 我有以下django模板(将http:// IP / admin / start /分配给一个名为view的假设视图): 是视图中引用的Django模型的。每当单击“开始”提交输入时,我都希望“开始”视图在返回渲染页面之前使用函数中的数据。如何将POST(在本例中为隐藏输入)中发布的信息收集到Python变量中? 问题答案: 另外,你的隐藏字段还需要一个可靠的名称,然后是一个值: 然后

  • 他们在vertx网站上的文档不太清楚如何接收请求的正文。 我得到错误: 如果他们甚至不把它放在他们的文件里,我怎么知道该怎么称呼它...

  • 问题内容: 所以我在与node.js一起运行的server.js文件中有以下代码。我正在使用express处理HTTP请求。 我在终端中运行以下命令: 运行该server.js后,将输出以下内容。 所以req.body是。我阅读了其他有关类似问题的Stack Overflow帖子,其中由于正文解析器,内容类型不正确。但这不是问题,因为内容类型是application / json。 有什么想法如何

  • 我很好奇是否有可能在nest.js的请求体中获取XML数据。 我希望有一个名为的HTTP POST API,它将获得如下所示的XML文档: 在我的控制器内: 但在记录传入请求正文时,我得到的只是。我的邮递员设置已经提到: 并且在中粘贴了上面提到的XML。响应是HTTP 400错误请求。 从nest.js中的请求体提取XML的通常方法是什么?