Android Volley POST 请求返回错误 400 (Bad Request)
Android Volley POST Request returning error 400 (Bad Request)
我正在尝试使用 Volley 库向 Azure IoT 中心发出 POST 请求,并使用 JAVA android 应用程序,但出现此错误:
BasicNetwork.performRequest:https://elca-iot.azure-devices.net/devices/elca-main-device/messages/events?api-version=2016-02-03)
的意外响应代码 400
要访问 IoT 中心,我需要使用 SAS 密钥,我需要将其包含在请求的 header 中。 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
看来问题出在 body content type
尝试在 getHeaders
和 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";
}
根据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."
所以请尝试如下更改您的代码。
在getHeaders
方法中添加Content-Type
header
params.put("Content-Type", "application/json");
改变getBodyContentType
方法的返回值,在getBody
方法中使用getBytes
和UTF-8
@Override
public String getBodyContentType() {
return "application/json; charset=UTF-8";
}
@Override
public byte[] getBody(){
return "On".getBytes("UTF-8");
}
看来问题出在地图中的值上。 []无法转义。
params.put("Authorization", "[My SAS Key]");
我所做的是,在创建参数时,我使用 UTF-8 对键和值进行了编码。
params.put("Authorization", URLEncoder.encode("[My SAS Key]", "UTF-8"));
我也被这个问题困扰了3天。这似乎是一种解决方法,但它对我有用。
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" 来发送 post 请求,然后根据 Volley 版本,您的调用将失败。只有 Volley 版本 1.1.1 将支持覆盖。 ('com.android.volley:volley:1.1.1')。所以我的建议是您必须遵循 3 个步骤。
- 发送您的 POST 请求而不用 content-type 并检查响应。如果是400就是你后端配置有问题
- 在构建 gradle
中将 volley 版本更改为 'com.android.volley:volley:1.1.1'
- 像这样 header 再次发送 POST 请求。
customHeaders.put("Content-Type","application/json");
现在应该可以了。
我正在尝试使用 Volley 库向 Azure IoT 中心发出 POST 请求,并使用 JAVA android 应用程序,但出现此错误: BasicNetwork.performRequest:https://elca-iot.azure-devices.net/devices/elca-main-device/messages/events?api-version=2016-02-03)
的意外响应代码 400要访问 IoT 中心,我需要使用 SAS 密钥,我需要将其包含在请求的 header 中。 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
看来问题出在 body content type
尝试在 getHeaders
和 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";
}
根据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."
所以请尝试如下更改您的代码。
在
getHeaders
方法中添加Content-Type
headerparams.put("Content-Type", "application/json");
改变
getBodyContentType
方法的返回值,在getBody
方法中使用getBytes
和UTF-8
@Override public String getBodyContentType() { return "application/json; charset=UTF-8"; } @Override public byte[] getBody(){ return "On".getBytes("UTF-8"); }
看来问题出在地图中的值上。 []无法转义。
params.put("Authorization", "[My SAS Key]");
我所做的是,在创建参数时,我使用 UTF-8 对键和值进行了编码。
params.put("Authorization", URLEncoder.encode("[My SAS Key]", "UTF-8"));
我也被这个问题困扰了3天。这似乎是一种解决方法,但它对我有用。
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" 来发送 post 请求,然后根据 Volley 版本,您的调用将失败。只有 Volley 版本 1.1.1 将支持覆盖。 ('com.android.volley:volley:1.1.1')。所以我的建议是您必须遵循 3 个步骤。
- 发送您的 POST 请求而不用 content-type 并检查响应。如果是400就是你后端配置有问题
- 在构建 gradle 中将 volley 版本更改为 'com.android.volley:volley:1.1.1'
- 像这样 header 再次发送 POST 请求。 customHeaders.put("Content-Type","application/json");
现在应该可以了。