带有标头和原始 json 正文的 Volley POST 请求
Posted
技术标签:
【中文标题】带有标头和原始 json 正文的 Volley POST 请求【英文标题】:Volley POST Request with headers and raw json body 【发布时间】:2020-01-02 01:28:42 【问题描述】:我正在尝试从 android 应用发出 Post 请求,该请求在请求正文中使用用户名和密码,并在标头中使用内容类型 application/json。
我尝试更改内容类型以及如何在正文中发送用户名密码,但仍然没有运气
public class MainActivity extends AppCompatActivity
private Button Login;
private EditText loginEmail, loginPassword;
String URL = "https://localhost:8080/api/v1/auth";
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loginEmail = (EditText)findViewById(R.id.etUsername);
loginPassword = (EditText)findViewById(R.id.etPassword);
Login = (Button)findViewById(R.id.btnLogin);
JSONObject jsonObject = new JSONObject();
try
jsonObject.put("username", loginEmail.getText().toString());
catch (JSONException e)
e.printStackTrace();
try
jsonObject.put("password", loginPassword.getText().toString());
catch (JSONException e)
e.printStackTrace();
final String requestBody = jsonObject.toString();
Login.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
StringRequest request = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>()
@Override
public void onResponse(String response)
Toast.makeText(MainActivity.this, response, Toast.LENGTH_LONG).show();
startActivity(new Intent(MainActivity.this, LandingPage.class));
finish();
, new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError error)
Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_LONG).show();
NetworkResponse response = error.networkResponse;
if (error instanceof ServerError && response != null)
try
String res = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, "utf-8"));
// Now you can use any deserializer to make sense of data
JSONObject obj = new JSONObject(res);
Toast.makeText(MainActivity.this, res, Toast.LENGTH_LONG).show();
Log.i("MainActivity", res);
//use this json as you want
catch (UnsupportedEncodingException e1)
// Couldn't properly decode data to string
e1.printStackTrace();
catch (JSONException e2)
// returned data is not JSONObject?
e2.printStackTrace();
)
@Override
public String getBodyContentType()
return "application/json; charset=utf-8";
@Override
public byte[] getBody() throws AuthFailureError
try
return requestBody == null ? null : requestBody.getBytes("utf-8");
catch (UnsupportedEncodingException uee)
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8");
return null;
@Override
public Map<String, String> getHeaders() throws AuthFailureError
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json");
return params;
;
RequestQueue rQueue = Volley.newRequestQueue(MainActivity.this);
rQueue.add(request);
);
来自 Postman 的 Post Request 工作得非常好,但 Volley 会引发错误 400。 以下是我在控制台中遇到的错误 "errorSummary":"错误请求。Accept 和/或 Content-Type 标头可能与支持的值不匹配。"
【问题讨论】:
您可以尝试使用自定义请求并扩展Request<JSONObject>
,而不是使用StringRequest
。就我而言,它是这样工作的。
@MaximilianSpeicher 你能提供一个示例代码吗?我对 android 很陌生
请稍等。
【参考方案1】:
尝试使用自定义请求并扩展Request<JSONObject>
:
CustomRequest
类:
public class CustomRequest extends Request<JSONObject>
private final Map<String, String> mHeaders;
private final JSONObject mBody;
private final Response.Listener<JSONObject> mResponseListener;
public CustomRequest(int method, String url, Map<String, String> headers, JSONObject body, Response.Listener<JSONObject> responseListener, Response.ErrorListener errorListener)
super(method, url, errorListener);
this.mHeaders = headers;
this.mBody = body;
this.mResponseListener = responseListener;
@Override
public Map<String, String> getHeaders() throws AuthFailureError
return mHeaders != null ? mHeaders : super.getHeaders();
@Override
public String getBodyContentType()
return "application/json; charset=UTF-8";
@Override
public byte[] getBody() throws AuthFailureError
return mBody != null ? mBody.toString().getBytes(Charset.forName("UTF-8")) : super.getBody();
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response)
try
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response));
catch (UnsupportedEncodingException | JSONException e)
return Response.error(new ParseError(e));
@Override
protected void deliverResponse(JSONObject response)
mResponseListener.onResponse(response);
用法:
String url = "https://localhost:8080/api/v1/auth";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
JSONObject jsonObject = new JSONObject();
try
jsonObject.put("username", loginEmail.getText().toString());
jsonObject.put("password", loginPassword.getText().toString());
catch (JSONException e)
e.printStackTrace();
CustomRequest customRequest = new CustomRequest(Request.Method.POST, url, headers, jsonObject, response ->
// put your reponse listener code here
, error ->
// put your error listener code here
);
RequestQueue queue = Volley.newRequestQueue(context);
queue.add(customRequest);
【讨论】:
我仍然收到错误 400。请查看有问题的 Postman 屏幕截图,看看是否可以找到需要更改的内容。 @JanakSoni 我忘了添加parseNetworkResponse
函数。您可以检查编辑并检查它现在是否有效。如果它不起作用,您是否检查过您是否从 EditText
获得了正确的用户名和密码,如果您使用的是 localhost,您的测试设备是否可以使用 API url?
我在 CustomRequest 中添加了 parseNetworkResponse。是的,我正在记录用户名和密码。它们是正确的。
您是刚刚添加了parseNetworkResponse
还是按照我编辑的方式实现了?
首先我刚刚生成了一个空的,现在我添加了你实现的方式。以上是关于带有标头和原始 json 正文的 Volley POST 请求的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Alamofire 中请求带有正文和标头的 JSON?
HttpClient postasync,带有自定义标头和应用程序/json,用于正文 C#