ส่งคำขอ POST พร้อมข้อมูล JSON โดยใช้ Volley


84

ฉันต้องการส่งJsonObjectRequestคำขอใหม่:

  • ฉันต้องการรับข้อมูล JSON (การตอบสนองจากเซิร์ฟเวอร์): ตกลง
  • ฉันต้องการส่งข้อมูลที่จัดรูปแบบ 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 ในโครงการของฉันด้วย

คำตอบ:


88

JsonObjectRequestยอมรับJSONObjectว่าเป็นร่างกาย

จากบทความบล็อกนี้ ,

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

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

นี่คือซอร์สโค้ดและ 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);
}

1
HashMapเป็นชนิดของการซ้ำซ้อนในตัวอย่างของคุณ คุณสามารถใส่ 'โทเค็น' ลงJSONObjectในแผนที่ตรงกลางได้โดยตรง
Itai Hanski

@shkschneider ฉันได้รับข้อผิดพลาดประเภทที่เข้ากันไม่ได้ใน jsonBody จำเป็นต้องแปลง String เป็น JSONObject หรือไม่
Karthikeyan Ve

1
@Karthikeyan คุณพูดถูกใช้new JSONObject("{\"type\":\"example\"}")แทน - ฉันไม่ดี
shkschneider

44

ฉันรู้ว่าเธรดนี้ค่อนข้างเก่า แต่ฉันมีปัญหานี้และฉันได้หาวิธีแก้ปัญหาที่ยอดเยี่ยมซึ่งมีประโยชน์มากสำหรับหลาย ๆ คนเพราะมันแก้ไข / ขยายคลัง Volley ในหลาย ๆ ด้าน

ฉันเห็นคุณสมบัติบางอย่างของวอลเลย์ที่ไม่รองรับ:

  • สิ่งนี้JSONObjectRequestไม่สมบูรณ์แบบ: คุณต้องคาดหวังJSONในตอนท้าย (ดูResponse.Listener<JSONObject>)
  • แล้วการตอบสนองที่ว่างเปล่า (เพียงแค่ 200 สถานะ) ล่ะ?
  • ฉันจะทำอย่างไรหากต้องการ POJO ของฉันโดยตรงจากResponseListener?

ฉันรวบรวมวิธีแก้ปัญหามากมายในคลาสทั่วไปขนาดใหญ่เพื่อให้มีวิธีแก้ปัญหาทั้งหมดที่ฉันยกมา

  /**
  * 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
         // ...
     }
 }

มันอาจจะดูเกินความสามารถ แต่มันค่อนข้างดีที่จะมีตัวสร้างเหล่านี้ทั้งหมดเพราะคุณมีทุกกรณี

(ตัวสร้างหลักไม่ได้ถูกกำหนดให้ใช้โดยตรงแม้ว่าจะเป็นไปได้ก็ตาม)

  1. คำขอพร้อมคำตอบที่แยกวิเคราะห์ไปยัง POJO / Headers ตั้งค่าด้วยตนเอง / POJO เพื่อส่ง
  2. คำขอพร้อมคำตอบแยกวิเคราะห์เป็น POJO / POJO เพื่อส่ง
  3. คำขอพร้อมคำตอบแยกวิเคราะห์เป็น POJO / String to Send
  4. คำขอพร้อมคำตอบแยกวิเคราะห์เป็น POJO (GET)
  5. คำขอพร้อมคำตอบแยกวิเคราะห์เป็น POJO (GET) / ส่วนหัวตั้งค่าด้วยตนเอง
  6. คำขอโดยไม่มีการตอบกลับ (200 - เนื้อหาว่างเปล่า) / ตั้งค่าส่วนหัวด้วยตนเอง / POJO เพื่อส่ง
  7. คำขอที่ไม่มีการตอบกลับ (200 - ร่างกายว่างเปล่า) / POJO ที่จะส่ง
  8. คำขอที่ไม่มีการตอบกลับ (200 - เนื้อความว่างเปล่า) / สตริงที่จะส่ง

แน่นอนเพื่อให้ใช้งานได้คุณต้องมี GSON Lib ของ Google เพียงเพิ่ม:

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

ไปยังการอ้างอิงของคุณ (เวอร์ชันปัจจุบันคือ2.3.1)


คำตอบที่ดีขอบคุณสำหรับการแบ่งปัน ฉันแค่เปลี่ยนประเภทของtoBeSentพารามิเตอร์จากObjectเป็นTเพื่อความปลอดภัยมากขึ้น
Diederik

ใช่ความคิดที่ดีอย่าลังเลที่จะแก้ไข! มันเป็นเรื่องของชุมชน: D (ตอนนี้ฉันใช้มือถือ)
Laurent Meyer

ฉันกำลังพยายามทำสิ่งที่คล้ายกัน แต่มันดีกว่าที่ฉันจะสร้าง ....
Manish Singla

1
เหมาะสำหรับทุกสถานการณ์ในการสื่อสารไคลเอนต์เซิร์ฟเวอร์
Mukesh

คำตอบที่ดีหากคุณสร้างบทช่วยสอนสำหรับสิ่งนี้มันก็ดีมาก
Ali Khaki

29
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);

อ้างถึง


10
  • สร้างออบเจ็กต์ของ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อินเทอร์เฟซเพื่อให้คุณสามารถมองเห็นได้ เป็นผู้รับมอบสิทธิ์แบบธรรมดาสำหรับคำขอ async

    public interface PostCommentResponseListener {
    public void requestStarted();
    public void requestCompleted();
    public void requestEndedWithError(VolleyError error);
    }
    
  • รวมสิทธิ์อินเทอร์เน็ตไว้ในAndroidManifest.xmlไฟล์

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

1
ไม่ตอบคำถาม. ไม่ใช่คำขอ json จริงและข้อมูลจะไม่ถูกส่งไปในเนื้อความของคำขอ
Renascienza

นี่เป็นประโยชน์ tnx
Diyaa

1
นี่คือคำขอข้อมูล POST ไม่ใช่คำขอ JSON โหวตลง ไม่ตอบคำถามเลย
Marc DiMillo

4
    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>() { ... });

1
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 ในเนื้อหา
Haseeb Zulfiqar

1

คุณยังสามารถส่งข้อมูลโดยการลบล้าง getBody()เมธอดของJsonObjectRequestคลาส ดังแสดงด้านล่าง.

    @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;
    }

0
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;
}

1
โปรดชี้แจงคำถามของคุณ
Alex Filatov

1
@AlexFilatov คำถามไหน
Thomas Ayoub
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.