Search code examples
spring-boothttprequesthttpclientresttemplate

400 Bad Request received using java.net.HTTPClient, but working fine with Spring RestTemplate & Postman on the same URL & body


I am trying to send a JSON POST request to a URL using HTTPClient in my Springboot application, but I am receiving a 400 status response from the server. However, when I send the same request using Postman, I receive the desired response from the server.

Here's my code:

// some dummy url:
String url = "http://88.22.199.111:5000/detect";

JSONObject json1 = new JSONObject();
json1.put("From", "Sawan");
json1.put("to", "Mohan");
json1.put("message", "is API working?");
json1.put("check_list", 1);

HttpClient httpClient = HttpClient.newBuilder().build();

HttpRequest httpRequest = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(json1.toString()))
        .build();

System.out.println(json1.toString());
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

System.out.println(httpResponse.statusCode());
System.out.println(httpResponse.body());

This is the output on the console:

{"check_list":1,"From":"Sawan","to":"Mohan","message":"is API working?"}
400
{"message": "The browser (or proxy) sent a request that this server could not understand."}

When I hit the same URL via Postman with the following details, I get the desired response from the server:

Request Type: POST

URL: same URL as above

cURL:

curl --location 'http://88.22.199.111:5000/detect' \
--header 'Content-Type: application/json' \
--data '{
    "From":"Sawan"
    ,"to":"Mohan"
    ,"message":"is API working?"
    ,"check_list":1
} '

Desired Output:

{
    "status": 200,
    "message": "Success",
    "timestamp": "2023-03-31 05:20:33.455868 +0000",
    "data": {
        "Message": "is API working?",
        "MessageTimeUTC": "Fri, 31 Mar 2023 05:20:33 GMT",
        "Message_By": "sawan",
        "Message_To": "mohan",
        "Message_Intended_For": "mohan",
        "Sentences": []
}

Also, when I use the RestTemplate class, it works fine and I get the desired output on the console but in the actual application I can't use RestTemplate class of springboot so I need help with this.

Is there anything wrong with my code? Do I need to include any additional headers in my request? Any help would be appreciated.


Solution

  • Hopefully this will get you closer. I don't have access to your server.

    I have compared what java.net.http.HttpClient sends with what Postman/cURL sends. The only differences I can see are the Accept, Upgrade & Http2-Settings headers, which I have added to the code below. The User-Agent header is not important. This should not make a difference but perhaps the server you are calling is very particular, eg it can't do http2.

    For these sorts of issues I find it very useful to fire requests at httpbin.org. It responds with everything it received.

    import java.io.IOException;
    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    
    import org.json.JSONObject;
    
    public class App 
    {
        public static void main( String[] args ) throws IOException, InterruptedException
        {
            String url = "http://88.22.199.111:5000/detect";
            // or url = "http://httpbin.org/post"; // this is very helpful
    
            JSONObject json1 = new JSONObject();
            json1.put("From", "Sawan");
            json1.put("to", "Mohan");
            json1.put("message", "is API working?");
            json1.put("check_list", 1);
    
            HttpClient httpClient = HttpClient
                .newBuilder()
                .version(Version.HTTP_1_1) // added this
                .build();
    
            HttpRequest httpRequest = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .header("Content-Type", "application/json")
                    .header("Accept", "*/*") // added this
                    .POST(HttpRequest.BodyPublishers.ofString(json1.toString()))
                    .build();
    
            System.out.println(json1.toString());
            HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
    
            System.out.println(httpResponse.statusCode());
            System.out.println(httpResponse.body());
        }
    }
    

    Perhaps also try RestTemplate to compare the working headers & payload with the failing ones.