Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write request to file in Spring MVC

I'd like to be able to write an entire request to a file within a Spring MVC controller.

I've tried the following, but the file is always empty even though I'm making a POST request with loads of parameters:

    @RequestMapping(method = RequestMethod.POST, value = "/payments/confirm")
public void receiveCallback(ServletInputStream inputStream)
{
    try
    {
        inputStream.reset();
        byte[] data = IOUtils.toByteArray(inputStream);

        File file = new File(System.getProperty("java.io.tmpdir") + "test" + System.currentTimeMillis() + ".txt");
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(data);
        fos.close();
    }
    catch (Exception e)
    {
        logger.error("Error writing request", e);
    }
}

I've also tried using HttpServletRequest.getInputStream(), but the same results.

like image 937
EngineerBetter_DJ Avatar asked Dec 16 '22 11:12

EngineerBetter_DJ


2 Answers

Using the InputStream won't work (see BalusC's answer). Here's a sample of how you could use a HTTPServletRequest object instead to write headers and parameters:

@RequestMapping(method = RequestMethod.POST, value = "/payments/confirm")
public void receiveCallback(HttpServletRequest request) {
    try {
        StringBuilder sb = new StringBuilder();
        sb.append("Headers:\n");
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            Enumeration<String> headers = request.getHeaders(headerName);
            while (headers.hasMoreElements()) {
                String headerValue = headers.nextElement();
                sb.append(headerName).append(':').append(headerValue).append('\n');
            }
        }
        sb.append("\nParameters:\n");
        for(Entry entry: (Set<Entry>) request.getParameterMap().entrySet(){
            sb.append(entry.getKey()).append(':').append(entry.getValue()).append('\n');
        }
        byte[] data = sb.toString().getBytes();

        File file = new File(System.getProperty("java.io.tmpdir") + "test"
                + System.currentTimeMillis() + ".txt");
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(data);
        fos.close();
    } catch (Exception e) {
        logger.error("Error writing request", e);
    }
}
like image 81
Sean Patrick Floyd Avatar answered Jan 01 '23 17:01

Sean Patrick Floyd


I know nothing about Spring, but I can at least tell that the POST request body can be read only once. It's namely the data whatever the client has sent to the server. The client ain't going to resend it multiple times whenever the server needs it multiple times.

I assume that Spring has already read the request body in order to parse the enclosed query string and get the request parameters before entering the Spring controller method. This can under Spring's covers be done with request.getParameter() and consorts. In the Servlet API, once that method is been called, the request.getInputStream() and request.getReader() won't return anything afterwards. Simply because the request body is already been read in order to return the parameters. This is also mentioned in the getParameter()'s javadoc.

If the parameter data was sent in the request body, such as occurs with an HTTP POST request, then reading the body directly via getInputStream() or getReader() can interfere with the execution of this method.

Your best bet is to create a filter which makes a copy of the request body before Spring does its job and then place the filter in front of the Spring controller. Making a copy of the request body is possible with help of a HttpServletRequestWrapper wherein you override getInputStream() and getReader() methods to first read the request body into a ByteArrayInputStream and/or a CharArrayReader so that you have a local copy and then return it instead. A reference to the HttpServletRequestWrapper could be stored as a request attribute so that you can obtain it as request attribute in the Spring controller and finally get the copy of the request body.

like image 20
BalusC Avatar answered Jan 01 '23 17:01

BalusC