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