Read HttpServletRequest object from Spring Boot controller method

27,807

Solution 1

First, remove the @Autowired field. It's wrong and you're not using it anyway.

Now you have two choices:

  1. Let Spring process the request body for you, by using the @RequestBody annotation:

    @PostMapping(path = "/abc")
    public String createAbc(@RequestBody String requestBody) throws IOException {
        logger.info("Request body: " + requestBody);
        return "abc";
    }
    
  2. Process it yourself, i.e. don't use the @RequestBody annotation:

    @PostMapping(path = "/abc")
    public String createAbc(HttpServletRequest request) throws IOException {
        StringBuilder builder = new StringBuilder();
        try (BufferedReader in = request.getReader()) {
            char[] buf = new char[4096];
            for (int len; (len = in.read(buf)) > 0; )
                builder.append(buf, 0, len);
        }
        String requestBody = builder.toString();
        logger.info("Request body: " + requestBody);
        return "abc";
    }
    

Don't know why you'd use option 2, but you can if you want.

Solution 2

if you want to take it out easily:

private ObjectMapper objectMapper;

byte[] bytes = request.getInputStream().readAllBytes();

User u = objectMapper.readValue(bytes, User.class);
Share:
27,807

Related videos on Youtube

bigdata123
Author by

bigdata123

Updated on January 24, 2022

Comments

  • bigdata123
    bigdata123 about 2 years

    Below is my controller method definition

    @Autowired
    private HttpServletRequest request;
    
    @PostMapping(path = "/abc")
    public String createAbc(@RequestBody HttpServletRequest request)
            throws IOException {
    
        logger.info("Request body: "+request.getInputStream());
    
        return "abc";
    
    }
    

    All i want to do is print contents to request body. But when i make a POST request i see below error:

    Type definition error: [simple type, class javax.servlet.http.HttpServletRequest]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of javax.servlet.http.HttpServletRequest (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information\n at [Source: (PushbackInputStream); line: 1, column: 2]",

    I'm using Spring boot 2.x version.Any idea what's wrong in my code?

    • Scary Wombat
      Scary Wombat over 4 years
      You already have autowired your request. Where did you get @RequestBody HttpServletRequest request from ?
  • Scary Wombat
    Scary Wombat over 4 years
    remove the @Autowired field. It's wrong - can you please explain why it is wrong ? Seen in stackoverflow.com/questions/3320674/…
  • Andreas
    Andreas over 4 years
    @ScaryWombat Well, true, it is wrong for a singleton bean. It is not wrong in that link you provided, since it explicitly says that it is a request-scoped bean. Since this question didn't specify that, the default type of bean is singleton, so it would be wrong. Besides, why create a request-scoped bean, when a singleton bean will suffice? Anyway, it is surely wrong to have HttpServletRequest as both an autowired field and as a parameter.
  • Scary Wombat
    Scary Wombat over 4 years
    the default type of bean is singleton, so it would be wrong - Thanks
  • Andreas
    Andreas over 4 years
    @ScaryWombat Yeah, you have to add another annotation to change the scope, e.g. @Scope(WebApplicationContext.SCOPE_REQUEST). Without a @Scope annotation, the bean is singleton.
  • 0x4ndy
    0x4ndy almost 4 years
    @Andreas one of the reasons you'd like to go for option 2 is when you don't receive the post as plain text but something like a gzip, that is sent by the client. You of course would not use the string builder to unzip the data but something like GZIPInputStream and dump it to a normal String, but that's one of the reasons why you would need to have access to HttpServletRequest. So, thanks for the answer mate, very helpful!
  • Andreas
    Andreas almost 4 years
    @4n0y If the content is gzipped, the request should have a header saying so, either Content-Encoding: gzip or Transfer-Encoding: gzip, and the unzipping should be applied by the framework before the data is received by the handler. With Spring, that does require a Filter, though. As such, you still wouldn't need to use option 2, which is a good thing, because repeating the unzipping and unmarshaling logic in every handler that needs to support gzip'd content would entirely fail the DRY principle.
  • 0x4ndy
    0x4ndy almost 4 years
    @Andreas Of course it should, but sometimes it doesn't, depending on where the request comes from and then you may want to handle the request differently. But regardless, the unzipping is not provided by the framework, and as you pointed out, you need to have a filter. Having access to HttpServletRequest in the controller, especially for a 2 additional lines of code to check for header and unzip is much more practical than providing a full-blown filter just for that - that's imho of course :-)