Marcos Felipe
Marcos Felipe

Reputation: 45

Android Volley POST Request returning error 400 (Bad Request)

I'm Trying to make a POST Request to Azure IoT Hub with a JAVA android application, using Volley Library, but I'm getting this error: BasicNetwork.performRequest: Unexpected response code 400 for https://elca-iot.azure-devices.net/devices/elca-main-device/messages/events?api-version=2016-02-03)

To access the IoT Hub I need to use a SAS Key that I need to include in the header of the request. The android application Code is below:

RequestQueue queue = Volley.newRequestQueue(c);
    String url = "https://elca-iot.azure-devices.net/devices/" + deviceId + "/messages/events?api-version=2016-02-03)";
    // Request a string response from the provided URL.
    StringRequest stringRequest = new StringRequest(Request.Method.POST,
            url, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            onPostResponse(response, c, true);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.d("Error", error.getMessage());
            onPostResponse(error.getMessage(), c, false);
        }
    }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            //params.put("Content-Type", "application/xml");
            params.put("Authorization", "[My SAS Key]");
            params.put("Cache-Control", "no-cache");
            return params;
        }
        /*
        @Override
        public Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            params.put("api-version","2016-02-03");
            return params;
        }*/
        @Override
        public String getBodyContentType() {
            return "application/text; charset=UTF-8";
        }
        @Override
        public byte[] getBody(){
            return "On".getBytes();
        }
    };
    try {
        Log.d("request", String.valueOf(stringRequest.getMethod()==Request.Method.POST));
    } catch (Exception authFailureError) {
        authFailureError.printStackTrace();
    }
    // Add the request to the RequestQueue.
    queue.add(stringRequest);

I've tried to do the same request using POSTMAN and it worked and I don't know why it isn't working with the Android Application. Here's the http code of the request made with POSTMAN:

    POST /devices/elca-main-device/messages/events?api-version=2016-02-03 HTTP/1.1
Host: elca-iot.azure-devices.net
Authorization: [My SAS Key]
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: d0aa354a-f79c-e574-893a-c259232aa5cb

on

EDIT:

Screenshot of POSTMAN

Upvotes: 2

Views: 5024

Answers (4)

Neyomal
Neyomal

Reputation: 1649

Android Volley POST request set Content-Type to value "application/json; charset=UTF-8" by default. If you set content type in your request call it will override your content type. For example if your send request "Content-Type", "application/json" then it will set the content type to "application/json". But if you remove it then automatically it set to "application/json; charset=UTF-8". Problem here is if your back end configured(written by the developers) only to manage "application/json" request then the default call "application/json; charset=UTF-8" would fail your request.(Problem with the back end development). But this will work fine in the POSTMAN. So can't figure out what is actually wrong here. Since you can send a post request by setting "Content-Type" to "application/json" then depend on Volley version your call will fail. Only Volley version 1.1.1 will support override. ('com.android.volley:volley:1.1.1'). So my advice is you have to follow 3 steps.

  1. Send your POST request with out content-type and check the response. If it is 400 it is a problem with your back end configuration.
  2. Change your volley version to 'com.android.volley:volley:1.1.1' in your build graddle
  3. Send POST request again as a header like this. customHeaders.put("Content-Type","application/json");

It should work now.

Upvotes: 1

Akash Agrawal
Akash Agrawal

Reputation: 36

It seems the problem lies in the value in the map. [] could not be escaped.

params.put("Authorization", "[My SAS Key]");

What I did was, while creating the params, I encoded key and value with UTF-8.

params.put("Authorization", URLEncoder.encode("[My SAS Key]", "UTF-8"));

I also struggled with this problem for 3 days. It may seem like a work around but it worked for me.

Upvotes: 2

Peter Pan
Peter Pan

Reputation: 24138

According to the Common error codes of Azure IoTHub, the 400 error code means "The body of the request is not valid; for example, it cannot be parsed, or the object cannot be validated."

Meanwhile, as the offical REST reference for Common parameters and headers said, "Set the Content-Type header to application/json."

So please try to change your code as below.

  1. Add the Content-Type header in the getHeaders method.

    params.put("Content-Type", "application/json");
    
  2. Change the reture value of the getBodyContentTypemethod, and use getBytes with UTF-8 in the getBody method.

    @Override
    public String getBodyContentType() {
        return "application/json; charset=UTF-8";
    }
    @Override
    public byte[] getBody(){
        return "On".getBytes("UTF-8");
    }
    

Upvotes: 0

Omid Heshmatinia
Omid Heshmatinia

Reputation: 5236

It seems the problem is with body content type Try adding it both in getHeaders and getBodyContentType

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            //params.put("Content-Type", "application/xml");
            params.put("Authorization", "[My SAS Key]");
            params.put("Cache-Control", "no-cache");
            params.put("Content-Type", "application/x-www-form-urlencoded");
            return params;
        }
        /*
        @Override
        public Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            params.put("api-version","2016-02-03");
            return params;
        }*/
        @Override
        public String getBodyContentType() {
            return "application/x-www-form-urlencoded; charset=UTF-8";
        }

Upvotes: 1

Related Questions