Android Volley POST请求返回错误400(错误请求)

时间:2017-05-04 03:09:02

标签: java android azure iot

我正在尝试使用Volley Library使用JAVA android应用程序向Azure IoT Hub发出POST请求,但是我收到此错误: BasicNetwork.performRequest:https://elca-iot.azure-devices.net/devices/elca-main-device/messages/events?api-version=2016-02-03

的意外响应代码400

要访问IoT Hub,我需要使用我需要包含在请求标头中的SAS密钥。 android应用程序代码如下:

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);

我尝试使用POSTMAN执行相同的请求并且它有效并且我不知道为什么它不能使用Android应用程序。这是使用POSTMAN发出的请求的http代码:

    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

编辑:

Screenshot of POSTMAN

4 个答案:

答案 0 :(得分:1)

似乎问题出在body content type 尝试在getHeadersgetBodyContentType

中添加它
        @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";
        }

答案 1 :(得分:1)

问题似乎在于地图中的价值。 []无法逃脱。

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

我所做的是,在创建参数时,我使用UTF-8编码键和值。

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

我也在这个问题上挣扎了3天。这似乎是一种解决方法,但它对我有用。

答案 2 :(得分:0)

根据Azure IoTHub的Common error codes,400错误代码表示 "The body of the request is not valid; for example, it cannot be parsed, or the object cannot be validated."

同时,正如Common parameters and headers的官方REST参考说的那样, "Set the Content-Type header to application/json."

因此,请尝试更改您的代码,如下所示。

  1. Content-Type方法中添加getHeaders标题。

    params.put("Content-Type", "application/json");
    
  2. 更改getBodyContentType方法的reture值,并在getBytes方法中将UTF-8getBody一起使用。

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

答案 3 :(得分:0)

Android Volley POST请求默认将Content-Type设置为“ application / json; charset = UTF-8”。如果您在请求调用中设置了内容类型,它将覆盖您的内容类型。 例如,如果您的发送请求“ Content-Type”,“ application / json”,则它将内容类型设置为“ application / json”。但是,如果将其删除,则会自动将其设置为“ application / json; charset = UTF-8”。这里的问题是,如果您的后端配置(由开发人员编写)仅管理“ application / json”请求,则默认调用“ application / json; charset = UTF-8”将使您的请求失败。(后端开发问题)。但这在POSTMAN中可以正常工作。所以无法弄清楚这里到底出了什么问题。由于您可以通过将“ Content-Type”设置为“ application / json”来发送发布请求,因此取决于Volley版本,您的呼叫将失败。仅Volley 1.1.1版将支持覆盖。 ('com.android.volley:volley:1.1.1')。所以我的建议是您必须遵循3个步骤。

  1. 发送不带内容类型的POST请求并检查响应。如果是400,则说明您的后端配置有问题。
  2. 在构建分级中将凌空版本更改为'com.android.volley:volley:1.1.1'
  3. 再次发送POST请求作为标头,如下所示。 customHeaders.put(“ Content-Type”,“ application / json”);

现在应该可以工作。