Spring Boot controller not responding to POST request

10,006

Solution 1

If you use Spring Boot 2, then it could happen because of the csrf-protection. It affects only the non-GET requests, and it's turned on by default on Spring Boot 2, but it's off in earlier versions.

So it quite well reflects your issue-description - although I don't fully understand how could it work via Postman... however there is a chance that it handles it automatically somehow...

Anyway it could worth a try:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
  }
}

Solution 2

Hi you are accessing REST service over HTTPS. The message you have recieved from the server is very clear.

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

You have not added the certificate to your ca store. A detailed step by step guide on how to do this is available here

Getting ssl.SSLHandshakeException when using REST client with header but works fine with PostMan

Solution 3

Whenever Java attempts to connect to another application over SSL (e.g.: HTTPS, IMAPS, LDAPS), it will only be able to connect to that application if it can trust it.

The way trust is handled in the Java world is that you have a keystore (typically $JAVA_HOME/lib/security/cacerts), also known as the truststore. This contains a list of all known Certificate Authority (CA) certificates, and Java will only trust certificates that are signed by one of those CAs or public certificates that exist within that keystore.

This problem is therefore caused by either a certificate that is self-signed (a CA did not sign it) or a certificate chain that does not exist within the Java truststore. It does not trust the certificate and fails to connect to the application.

Solution 4

I am not sure which format while you issue post request. You could use the postman to verify which kind of post you application could handle. And send the same kind of post request, I believe you could find the sample code easily for each of them. Usually, while we submit post from html page, we use x-www-form-urlencoded.

post methods from post man

Share:
10,006

Related videos on Youtube

Mats Andersson
Author by

Mats Andersson

Java programmer, DBA, and systems architect working with all parts from database to web GUI.

Updated on September 15, 2022

Comments

  • Mats Andersson
    Mats Andersson over 1 year

    I am working with a receipt printer that has a cloud function. It commuicates with a server specification which i am implementing. It polls a URL with POST requests every x seconds and when the POST response contains a certain piece of information, the printer sends a GET request to the same to URL get the information to print.

    I'm implementing the print server as a Spring Boot server and i'm getting some strange problems with the POST method that i need some help with.

    My problem is that the POST requests from the printer to the server never make it to the controller. However, i am able to send a POST request from Postman to the exact same URL and it gets handled by the controller.

    The URL is simply: https://www.[my-domain].com:[port-number]/cloudprint

    Also, i have tried copying the controller method to another Spring (not Boot) application, running on a Tomcat instance behind Apache and there, the POST requests from the printer are handled by the controller method. I can see them in the Apache log and the Tomcat log. The polling frequency is currently at 10 seconds.

    Here's what the controller looks like:

    package com.[my-domain].[application-name].controller;
    
    [a bunch of imports]
    
    @RestController
    @CrossOrigin
    public class PrintController {
        Logger logger = LoggerFactory.getLogger(PrintController.class);
    
        @RequestMapping(value="/cloudprint", method=RequestMethod.POST,
                headers={"Accept=application/json"})
        @ResponseStatus(HttpStatus.CREATED)
        public @ResponseBody String printPost() { 
            logger.debug("in printPost");
            return "OK";
        }
    
        @RequestMapping(value="/cloudprint", method=RequestMethod.GET,
                headers={"Accept=application/json"})
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody String printGet(HttpServletRequest request) {
            logger.debug("in printGet");
            return "OK";
        }
    
        @RequestMapping(value="/cloudprint", method=RequestMethod.DELETE,
                headers={"Accept=application/json"})
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody String printDelete() {
            logger.debug("in printDelete");
            return "OK";
        }
    }
    

    What could be causing this? What can i test to solve this issue?

    ---ADDED INFORMATION BELOW 2019-06-03 @13:21 cet--- Since i have a regular Spring (non-boot) application that accepts the POST requests from the printer, i am able to log the information in the incoming request. So i did that.

    This is one of the POST requests from the printer, which is NOT accepted by the Spring boot oontroller:

    auth type: null
    content type: application/json
    -- HEADERS --
    Header: host : dev.[our-domain-name].com
    Header: accept : */*
    Header: user-agent : Cente HTTPc
    Header: content-type : application/json
    Header: content-length : 303
    Header: connection : keep-alive
    QueryString: null
    -- PARAMETERS --
    END
    

    This is one of the POST requests from Postman to the exact same URL, which IS accepted by the Spring boot oontroller:

    auth type: null
    cotent type: application/json
    -- HEADERS --
    Header: content-type : application/json
    Header: cache-control : no-cache
    Header: Postman-Token : caf99fa1-4730-4193-aab3-c4874273661d
    Header: user-agent : PostmanRuntime/7.6.0
    Header: accept : */*
    Header: host : dev.[our-domain-name].com
    Header: accept-encoding : gzip, deflate
    Header: content-length : 0
    Header: connection : keep-alive
    QueryString: null
    -- PARAMETERS --
    END
    

    Analysis: 1. The user-agent headers differ. 2. The content-length headers differ. 3. The Postman request has three headers that the request from the cloud printer does not have. They are: cache-control, Postman-token and accept-encoding

    ---ADDED INFORMATION BELOW 2019-06-03 @17:56 cet--- OK, i figured out how to log the message body. It is a well-formatted json structure that is indeed 303 characters:

    {"status": "29 a 0 0 0 0 0 0 0 0 0 0",
     "printerMAC": "00:11:62:1b:xx:xx",
     "statusCode": "200%20OK",
     "printingInProgress": false,
     "clientAction": null,
     "display": [
       {"name": "MainDisplay" ,
        "status": {"connected": false}}],
     "barcodeReader": [
       {"name": "MainBCR" ,
        "status": {"connected": false,"claimed": false}}]}
    

    I created the corresponding classes and changed the POST method in the Boot application to this:

    @RequestMapping(value="/cloudprint", method=RequestMethod.POST,
            headers={"Accept=application/json"})
    @ResponseStatus(HttpStatus.CREATED)
    public @ResponseBody String printPost(@RequestBody PrinterPostRequest printerPostRequest,
            HttpServletRequest request) {  
        HttpRequestLogger.log(request);
        return "OK";
    }
    

    Still, it is not picking up the POST request from the printer. It picks up the Postman request and successfully marshals the request body json into the classes.

    ---ADDED INFORMATION BELOW 2019-06-05 @10:16 cet--- I had an idea. Using Spring RestTemplate, i sent a POST request to the Boot application with the same headers and same payload as the request the printer sends. I'm getting an org.springframework.web.client.ResourceAccessException with this message:

    I/O error on POST request for "https://boot.[my-domain].com:8443/cloudprint":sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    
    • helospark
      helospark almost 5 years
      @MatsAndersson And do you have a valid SSL certificate or is it self-signed? Spring Boot does the SSL termination or do you have a front proxy?
    • stacker
      stacker almost 5 years
      I think it's @CrossOrigin, can you remove it and test again?
    • stacker
      stacker almost 5 years
      @MatsAndersson do you have any CORS config?
    • Sambit
      Sambit
      First run your application locally, if the port is 8080, then try to make a post call using the localhost:8080/cloudprint and check
  • Mats Andersson
    Mats Andersson almost 5 years
    i added a configuration class like the one you suggested, but unfortunately it made no difference. I still think this is worth digging deeper into. I will do that tomorrow when i'm back at work. I appreciate your input.
  • Meziane
    Meziane almost 5 years
    You must have an error in your Spring Boot Application as you are able to send to acces the POST request from Postman. So show us your code where you send the POST request in your Spring Boot application.
  • Mats Andersson
    Mats Andersson almost 5 years
    @meziane: I do not send a POST request in my Spring Boot application. I receive one. The request is sent from a receipt printer, as i clearly stated in my original post. Here's the printer: star-emea.com/products/cloudprnt
  • Meziane
    Meziane almost 5 years
    @mats-andersson sorry I misunderstand you: I needed a coffee (:
  • Meziane
    Meziane almost 5 years
    Are you sending anything in the body of your POST request? As you can see here not sending a body is not allowed, as the default value of the required attribute of @RequestBody is true.
  • Mats Andersson
    Mats Andersson almost 5 years
    I have added a block of information about the requests at the bottom of the thread. I am also setting up a bounty for it now.
  • Mats Andersson
    Mats Andersson almost 5 years
    @Mezaine: the root problem is that i am not in control of what the printer sends. It's an off-the-shelf printer with a built-in cloud printing functionality.
  • Meziane
    Meziane almost 5 years
    @mats-andersson Sorry but I have not time to look how the printer sends the POST requests. But may be a filter can help there to check if the POST-requests reach the destination: may be they are rejected if in case there is no body content (RequestBody is empty), but than an an exception must be thrown (You didn't set the attribute required to false, did you? )
  • Meziane
    Meziane almost 5 years
    In your printPost-method you must have a @RequestBody: public @ResponseBody String printPost(@RequestBody AnyClass anyClass) { logger.debug("in printPost"); return "OK"; }
  • Mats Andersson
    Mats Andersson almost 5 years
    @Mezaine I don't understand the logic here. How would you explain that the post to the exact same URL but from Postmaster is successfully picked up by the controller?
  • Meziane
    Meziane almost 5 years
  • MarkOfHall
    MarkOfHall almost 5 years
    I would start with DEBUG level logging on Spring Web. If you don't see the POST request in the logs, then it is obviously not your app. logging.level.org.springframework.web: DEBUG
  • Mats Andersson
    Mats Andersson almost 5 years
    I have set: <logger name="org.springframework" level="debug" > and still i don't see these post requests in the log. They're not even making it to Spring then...
  • Mats Andersson
    Mats Andersson almost 5 years
    Yes that's what i suspected. Is a Let's encrypt certificate really not considered OK? That's what i have.
  • Mats Andersson
    Mats Andersson almost 5 years
    It comes from a cloud printer and i do not have access to its code, just their documentation, which does not cover the format. Please read the entire thread. The issue is pretty well described IMHO.