使用 Volley 发送带有 JSON 数据的 POST 请求

Posted

技术标签:

【中文标题】使用 Volley 发送带有 JSON 数据的 POST 请求【英文标题】:Send POST request with JSON data using Volley 【发布时间】:2014-06-06 21:25:52 【问题描述】:

我想发送一个新的JsonObjectRequest 请求:

我想接收 JSON 数据(来自服务器的响应):OK

我想通过这个请求向服务器发送 JSON 格式的数据

JsonObjectRequest request = new JsonObjectRequest(
    Request.Method.POST, "myurl.com", null,
    new Response.Listener<JSONObject>() 
        @Override
        public void onResponse(JSONObject response) 
            //...
        
    ,
    new Response.ErrorListener() 
        @Override
        public void onErrorResponse(VolleyError error) 
            //...
        
    )
    
        @Override
        protected Map<String,String> getParams() 
            // something to do here ??
            return params;
        

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError 
            // something to do here ??
            return params;
        
    ;

附:我也在我的项目中使用 GSON 库。

【问题讨论】:

【参考方案1】:

JsonObjectRequest 实际上接受 JSONObject 作为正文。

来自this blog article,

final String url = "some/url";
final JSONObject jsonBody = new JSONObject("\"type\":\"example\"");

new JsonObjectRequest(url, jsonBody, new Response.Listener<JSONObject>()  ... );

这里是source code and JavaDoc (@param jsonRequest):

/**
 * Creates a new request.
 * @param method the HTTP method to use
 * @param url URL to fetch the JSON from
 * @param jsonRequest A @link JSONObject to post with the request. Null is allowed and
 *   indicates no parameters will be posted along with request.
 * @param listener Listener to receive the JSON response
 * @param errorListener Error listener, or null to ignore errors.
 */
public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
        Listener<JSONObject> listener, ErrorListener errorListener) 
    super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
                errorListener);

【讨论】:

HashMap 在您的示例中有点多余。您可以将“令牌”直接放入JSONObject,而无需中间映射。 @shkschneider 我在 jsonBody 上遇到类型不兼容的错误。是否需要将 String 转换为 JSONObject ? @KarthikeyanVe 你是对的,改用new JSONObject("\"type\":\"example\"")——我的错。【参考方案2】:

我知道这个帖子已经很老了,但是我遇到了这个问题,我想出了一个很酷的解决方案,它对许多人来说非常有用,因为它在许多方面纠正/扩展了 Volley 库。

我发现了一些不受支持的开箱即用 Volley 功能:

这个JSONObjectRequest 并不完美:您必须在结尾处期待JSON(请参阅Response.Listener&lt;JSONObject&gt;)。 Empty Responses(只有 200 状态)呢? 如果我想直接从ResponseListener 获取我的 POJO,我该怎么办?

我或多或少在一个大的泛型类中编译了很多解决方案,以便为我引用的所有问题找到解决方案。

  /**
  * Created by laurentmeyer on 25/07/15.
  */
 public class GenericRequest<T> extends JsonRequest<T> 

     private final Gson gson = new Gson();
     private final Class<T> clazz;
     private final Map<String, String> headers;
     // Used for request which do not return anything from the server
     private boolean muteRequest = false;

     /**
      * Basically, this is the constructor which is called by the others.
      * It allows you to send an object of type A to the server and expect a JSON representing a object of type B.
      * The problem with the #JsonObjectRequest is that you expect a JSON at the end.
      * We can do better than that, we can directly receive our POJO.
      * That's what this class does.
      *
      * @param method:        HTTP Method
      * @param classtype:     Classtype to parse the JSON coming from the server
      * @param url:           url to be called
      * @param requestBody:   The body being sent
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      * @param headers:       Added headers
      */
     private GenericRequest(int method, Class<T> classtype, String url, String requestBody,
                           Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) 
         super(method, url, requestBody, listener,
                 errorListener);
         clazz = classtype;
         this.headers = headers;
         configureRequest();
     

     /**
      * Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and not muted)
      *
      * @param method:        HTTP Method
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      * @param headers:       Added headers
      */
     public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
                           Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) 
         this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                 errorListener, headers);
     

     /**
      * Method to be called if you want to send some objects to your server via body in JSON of the request (without header and not muted)
      *
      * @param method:        HTTP Method
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      */
     public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
                           Response.Listener<T> listener, Response.ErrorListener errorListener) 
         this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                 errorListener, new HashMap<String, String>());
     

     /**
      * Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)
      *
      * @param method:        HTTP Method
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param requestBody:   String to be sent to the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      */
     public GenericRequest(int method, String url, Class<T> classtype, String requestBody,
                           Response.Listener<T> listener, Response.ErrorListener errorListener) 
         this(method, classtype, url, requestBody, listener,
                 errorListener, new HashMap<String, String>());
     

     /**
      * Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (Without header)
      *
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      */
     public GenericRequest(String url, Class<T> classtype, Response.Listener<T> listener, Response.ErrorListener errorListener) 
         this(Request.Method.GET, url, classtype, "", listener, errorListener);
     

     /**
      * Method to be called if you want to GET something from the server and receive the POJO directly after the call (no JSON). (With headers)
      *
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      * @param headers:       Added headers
      */
     public GenericRequest(String url, Class<T> classtype, Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers) 
         this(Request.Method.GET, classtype, url, "", listener, errorListener, headers);
     

     /**
      * Method to be called if you want to send some objects to your server via body in JSON of the request (with headers and muted)
      *
      * @param method:        HTTP Method
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      * @param headers:       Added headers
      * @param mute:          Muted (put it to true, to make sense)
      */
     public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
                           Response.Listener<T> listener, Response.ErrorListener errorListener, Map<String, String> headers, boolean mute) 
         this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                 errorListener, headers);
         this.muteRequest = mute;
     

     /**
      * Method to be called if you want to send some objects to your server via body in JSON of the request (without header and muted)
      *
      * @param method:        HTTP Method
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param toBeSent:      Object which will be transformed in JSON via Gson and sent to the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      * @param mute:          Muted (put it to true, to make sense)
      */
     public GenericRequest(int method, String url, Class<T> classtype, Object toBeSent,
                           Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) 
         this(method, classtype, url, new Gson().toJson(toBeSent), listener,
                 errorListener, new HashMap<String, String>());
         this.muteRequest = mute;

     

     /**
      * Method to be called if you want to send something to the server but not with a JSON, just with a defined String (without header and not muted)
      *
      * @param method:        HTTP Method
      * @param url:           URL to be called
      * @param classtype:     Classtype to parse the JSON returned from the server
      * @param requestBody:   String to be sent to the server
      * @param listener:      Listener of the request
      * @param errorListener: Error handler of the request
      * @param mute:          Muted (put it to true, to make sense)
      */
     public GenericRequest(int method, String url, Class<T> classtype, String requestBody,
                           Response.Listener<T> listener, Response.ErrorListener errorListener, boolean mute) 
         this(method, classtype, url, requestBody, listener,
                 errorListener, new HashMap<String, String>());
         this.muteRequest = mute;

     


     @Override
     protected Response<T> parseNetworkResponse(NetworkResponse response) 
         // The magic of the mute request happens here
         if (muteRequest) 
             if (response.statusCode >= 200 && response.statusCode <= 299) 
                 // If the status is correct, we return a success but with a null object, because the server didn't return anything
                 return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
             
          else 
             try 
                 // If it's not muted; we just need to create our POJO from the returned JSON and handle correctly the errors
                 String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                 T parsedObject = gson.fromJson(json, clazz);
                 return Response.success(parsedObject, HttpHeaderParser.parseCacheHeaders(response));
              catch (UnsupportedEncodingException e) 
                 return Response.error(new ParseError(e));
              catch (JsonSyntaxException e) 
                 return Response.error(new ParseError(e));
             
         
         return null;
     

     @Override
     public Map<String, String> getHeaders() throws AuthFailureError 
         return headers != null ? headers : super.getHeaders();
     

     private void configureRequest() 
         // Set retry policy
         // Add headers, for auth for example
         // ...
     
 

这似乎有点矫枉过正,但拥有所有这些构造函数非常酷,因为您拥有所有案例:

(虽然可以直接使用主构造函数,但它当然是可能的)。

    请求的响应解析为 POJO/标头手动设置/POJO 发送 响应解析为 POJO/POJO 以发送的请求 响应解析为 POJO/要发送的字符串的请求 响应解析为 POJO (GET) 的请求 响应解析为 POJO (GET) 的请求/手动设置的标头 请求无响应(200 - 空正文)/手动设置标头/要发送的 POJO 没有响应的请求(200 - 空正文)/要发送的 POJO 没有响应的请求(200 - 空正文)/要发送的字符串

当然,为了让它工作,你必须有谷歌的 GSON Lib;只需添加:

compile 'com.google.code.gson:gson:x.y.z'

到您的依赖项(当前版本是2.3.1)。

【讨论】:

好答案,感谢分享。我只需将 toBeSent 参数的类型从 Object 更改为 T 以提高类型安全性。 是的,好主意,随时编辑!这是社区的东西:D(我目前在移动) 我也在尝试做类似的事情,但它比我要创建的要好得多...... 好一个适合客户端服务器通信中的所有场景。 很好的答案。如果您为此创建一些教程非常好【参考方案3】:
final String URL = "/volley/resource/12";
// Post params to be sent to the server
HashMap<String, String> params = new HashMap<String, String>();
params.put("token", "AbCdEfGh123456");

JsonObjectRequest req = new JsonObjectRequest(URL, new JSONObject(params),
       new Response.Listener<JSONObject>() 
           @Override
           public void onResponse(JSONObject response) 
               try 
                   VolleyLog.v("Response:%n %s", response.toString(4));
                catch (JSONException e) 
                   e.printStackTrace();
               
           
       , new Response.ErrorListener() 
           @Override
           public void onErrorResponse(VolleyError error) 
               VolleyLog.e("Error: ", error.getMessage());
           
       );

// add the request object to the queue to be executed
ApplicationController.getInstance().addToRequestQueue(req);

refer

【讨论】:

【参考方案4】:

创建RequestQueue 类的对象。

RequestQueue queue = Volley.newRequestQueue(this);

创建一个带有响应和错误侦听器的StringRequest

 StringRequest sr = new StringRequest(Request.Method.POST,"http://api.someservice.com/post/comment", new Response.Listener<String>() 
    @Override
    public void onResponse(String response) 
        mPostCommentResponse.requestCompleted();
    
, new Response.ErrorListener() 
    @Override
    public void onErrorResponse(VolleyError error) 
        mPostCommentResponse.requestEndedWithError(error);
    
)
    @Override
    protected Map<String,String> getParams()
        Map<String,String> params = new HashMap<String, String>();
        params.put("user",userAccount.getUsername());
        params.put("pass",userAccount.getPassword());
        params.put("comment", Uri.encode(comment));
        params.put("comment_post_ID",String.valueOf(postId));
        params.put("blogId",String.valueOf(blogId));

        return params;
    

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError 
        Map<String,String> params = new HashMap<String, String>();
        params.put("Content-Type","application/x-www-form-urlencoded");
        return params;
    
;

将您的请求添加到RequestQueue

queue.add(jsObjRequest);

创建PostCommentResponseListener 界面,以便您可以看到它。这是异步请求的简单委托。

public interface PostCommentResponseListener 
public void requestStarted();
public void requestCompleted();
public void requestEndedWithError(VolleyError error);

androidManifest.xml 文件中包含 INTERNET 权限。

<uses-permission android:name="android.permission.INTERNET"/>

【讨论】:

不回答问题。 Not 是真正的 json 请求,请求体中没有发送数据。 这很有帮助。 tnx 这是一个 POST 数据请求,而不是 JSON 请求。否决票。根本不回答问题。【参考方案5】:
    final String url = "some/url";

代替:

    final JSONObject jsonBody = "\"type\":\"example\"";

你可以使用:

  JSONObject jsonBody = new JSONObject();
    try 
        jsonBody.put("type", "my type");
     catch (JSONException e) 
        e.printStackTrace();
    
new JsonObjectRequest(url, jsonBody, new Response.Listener<JSONObject>()  ... );

【讨论】:

【参考方案6】:

您还可以通过覆盖JsonObjectRequest 类的getBody() 方法来发送数据。如下图。

    @Override
    public byte[] getBody()
    

        JSONObject jsonObject = new JSONObject();
        String body = null;
        try
        
            jsonObject.put("username", "user123");
            jsonObject.put("password", "Pass123");

            body = jsonObject.toString();
         catch (JSONException e)
        
            // TODO Auto-generated catch block
            e.printStackTrace();
        

        try
        
            return body.toString().getBytes("utf-8");
         catch (UnsupportedEncodingException e)
        
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        return null;
    

【讨论】:

【参考方案7】:
final Map<String,String> params = new HashMap<String,String>();
        params.put("email", customer.getEmail());
        params.put("password", customer.getPassword());
        String url = Constants.BASE_URL+"login";

doWebRequestPost(url, params);


public void doWebRequestPost(String url, final Map<String,String> json)
        getmDialogListener().showDialog();

    StringRequest post = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() 
        @Override
        public void onResponse(String response) 
            try 
                getmDialogListener().dismissDialog();
                response....

             catch (Exception e) 
                e.printStackTrace();
            
        
    , new Response.ErrorListener() 
        @Override
        public void onErrorResponse(VolleyError error) 
            Log.d(App.TAG,error.toString());
            getmDialogListener().dismissDialog();

        
    )
        @Override
        protected Map<String, String> getParams() throws AuthFailureError 
            Map<String,String> map = json;

            return map;
        
    ;
    App.getInstance().getRequestQueue().add(post);


【讨论】:

这不会在正文中添加参数作为 JSON 数据【参考方案8】:
protected Map<String, String> getParams() 
   Map<String, String> params = new HashMap<String, String>();

   JSONObject JObj = new JSONObject();

   try 
           JObj.put("Id","1");
           JObj.put("Name", "abc");

    catch (Exception e) 
       e.printStackTrace();
   

   params.put("params", JObj.toString());
   // Map.Entry<String,String>
   Log.d("Parameter", params.toString());
   return params;

【讨论】:

请澄清您的问题 @AlexFilatov 哪个问题?

以上是关于使用 Volley 发送带有 JSON 数据的 POST 请求的主要内容,如果未能解决你的问题,请参考以下文章

Android Kotlin Volley 如何发送 JSON 数据

带有参数的 Volley jsonObjectRequest 不起作用

在 json 对象参数 Volley post 中发送令牌头

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

删除带有标头和参数的请求 Volley

如何在 android 中使用 Gson 或 VOLley 从 json 中删除空值