带有标头和原始 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&lt;JSONObject&gt;,而不是使用StringRequest。就我而言,它是这样工作的。 @MaximilianSpeicher 你能提供一个示例代码吗?我对 android 很陌生 请稍等。 【参考方案1】:

尝试使用自定义请求并扩展Request&lt;JSONObject&gt;

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 请求的主要内容,如果未能解决你的问题,请参考以下文章

如何通过带有标头的 volley 发布 JSON 请求?

如何在 Alamofire 中请求带有正文和标头的 JSON?

HttpClient postasync,带有自定义标头和应用程序/json,用于正文 C#

Volley Android中带有JSON正文的POST请求

使用原始请求标头 C# 在请求正文中发送参数和文件

带有标头和正文的 HTTPClient 发布请求