Volley - parametry POST / GET

81

Widziałem sesję Google IO 2013 o Volley i rozważam przejście na volley. Czy Volley obsługuje dodawanie parametrów POST / GET do żądania? Jeśli tak, jak mogę to zrobić?

Ziem
źródło
2
Nie widziałem całej keynote, ale jestem prawie pewien, że GET powinno być wykonalne po prostu przez dodanie parametrów do adresu URL (np. http://example.com?param1=val1&param2=val2)
JJJollyjim
Wydaje się, że nie ma jeszcze dokumentacji, ale możesz sprawdzić źródło tutaj android.googlesource.com/platform/frameworks/volley/+/master
MM.
@ JJ56 - Racja, ale co z parametrami POST? Widziałem kod źródłowy, ale nie znalazłem nic związanego z parametrami POST.
Ziem
1
Wstyd mi to powiedzieć. Ale jeśli pojawi się tutaj pytanie, dlaczego żądanie nie ma treści na serwerze, upewnij się, że używasz metody POST / PUT. Chyba jestem po prostu zmęczony. Mam nadzieję, że ten komentarz pomoże komukolwiek lub pomoże mi poczuć się lepiej
Alwin Kesler

Odpowiedzi:

64

W swojej klasie Request (która rozszerza Request), zastąp metodę getParams (). Zrobiłbyś to samo dla nagłówków, po prostu przesłoniłbyś getHeaders ().

Jeśli spojrzysz na klasę PostWithBody w TestRequest.java w testach Volley, znajdziesz przykład. To wygląda mniej więcej tak

public class LoginRequest extends Request<String> {

    // ... other methods go here

    private Map<String, String> mParams;

    public LoginRequest(String param1, String param2, Listener<String> listener, ErrorListener errorListener) {
        super(Method.POST, "http://test.url", errorListener);
        mListener = listener;
        mParams = new HashMap<String, String>();
        mParams.put("paramOne", param1);
        mParams.put("paramTwo", param2);

    }

    @Override
    public Map<String, String> getParams() {
        return mParams;
    }
}

Evan Charlton był na tyle uprzejmy, że wykonał krótki przykładowy projekt, aby pokazać nam, jak używać woleja. https://github.com/evancharlton/folly/

Afzal N
źródło
71
Zwróć uwagę, że getParamsjest on wywoływany (domyślnie) tylko w żądaniu POST lub PUT, ale nie w żądaniu GET. Zobacz odpowiedź Ogre_BGR
Itai Hanski
2
Nie mogę uwierzyć, że nigdy tego nie zauważyłem
Afzal N,
@AfzalivE, masz pomysł jak podpisać żądanie API za pomocą OAuth, używając powyższego kodu?
Bipin Vayalu
2
@BipinVayalu Jeśli łączysz się z Google API, powinieneś móc korzystać z com.android.volley.AndroidAuthenticator
Pierre-Antoine
Zapomniałeś utworzyć instancję mParams.
Moritz
85

Dla parametrów GET istnieją dwie możliwości:

Po pierwsze : jak zasugerowano w komentarzu pod pytaniem, możesz po prostu użyć ciągu znaków i zastąpić symbole zastępcze parametrów ich wartościami, takimi jak:

String uri = String.format("http://somesite.com/some_endpoint.php?param1=%1$s&param2=%2$s",
                           num1,
                           num2);

StringRequest myReq = new StringRequest(Method.GET,
                                        uri,
                                        createMyReqSuccessListener(),
                                        createMyReqErrorListener());
queue.add(myReq);

gdzie num1 i num2 to zmienne typu String, które zawierają Twoje wartości.

Po drugie : jeśli używasz nowszego zewnętrznego HttpClient (na przykład 4.2.x), możesz użyć URIBuilder do zbudowania Uri. Zaletą jest to, że jeśli ciąg znaków uri zawiera już parametry, łatwiej będzie go przekazać do, URIBuildera następnie użyć ub.setQuery(URLEncodedUtils.format(getGetParams(), "UTF-8"));do dodania dodatkowych parametrów. W ten sposób nie zadasz sobie trudu, aby sprawdzić, czy „? jest już dodany do URI lub pominąć niektóre, co eliminuje źródło potencjalnych błędów.

Dla parametrów POST pewnie czasami będzie łatwiej niż zaakceptowana odpowiedź to zrobić tak:

StringRequest myReq = new StringRequest(Method.POST,
                                        "http://somesite.com/some_endpoint.php",
                                        createMyReqSuccessListener(),
                                        createMyReqErrorListener()) {

    protected Map<String, String> getParams() throws com.android.volley.AuthFailureError {
        Map<String, String> params = new HashMap<String, String>();
        params.put("param1", num1);
        params.put("param2", num2);
        return params;
    };
};
queue.add(myReq);

np. po prostu nadpisać getParams()metodę.

Możesz znaleźć działający przykład (wraz z wieloma innymi podstawowymi przykładami Volley) w projekcie Andorid Volley Examples .

Ognyan
źródło
Podążałem za twoim przykładem Volley. Jak dotąd jest to najbardziej pomocny kod Volly, ale mam problemy w JsonObjectRequest. Otrzymałem starą odpowiedź w createMyReqSuccessListener do czasu ponownej instalacji. Czy Volley przechowuje dane w pamięci podręcznej? Zaproponuj sposób, jak to zrobić.
SkyWalker,
2
Buforowane są tylko obrazy. Sprawdź, czy istnieje serwer proxy przechwytujący Twoje żądania. Jeśli żądania mają dokładnie ten sam adres URL i możliwe, że serwer proxy po prostu zwraca pierwszy wynik.
Ognyan
2
Istnieje wtyczka do przeglądarki Firefox o nazwie „test zasobów HTTP”, która umożliwia wysyłanie żądań do serwera WWW. Jest to bardzo przydatne do testowania takich przypadków. Po prostu wprowadź swój adres URL (i parametry POST, jeśli istnieją) i zobacz, jaka jest odpowiedź serwera na wiele kolejnych żądań. Jeśli ponownie otrzymasz tę samą odpowiedź, najprawdopodobniej zostanie ona zapisana w pamięci podręcznej. W takim przypadku możesz sprawdzić zwrócone nagłówki, aby sprawdzić, czy istnieją nagłówki proxy. O "no-cache" - tak, powinno działać.
Ognyan
2
Sugeruję, abyś otworzył oddzielne pytanie, aby inni mogli dołączyć i pomóc. Podaj informacje, z jakiego stosu korzystasz HURL lub HttpClient, a także wersję Androida, na której testujesz. Proszę, umieść tutaj link do nowego pytania, aby ludzie mogli śledzić dyskusję.
Ognyan
3
@Yousif Prawdopodobnie otrzymasz dużo lepsze odpowiedzi, jeśli zadasz to jako nowe pytanie, ale w skrócie: żądanie POST pozwala na wysyłanie plików i innych większych danych, które nie zmieszczą się w żądaniu GET. Podczas korzystania z żądania GET istnieje również zagrożenie bezpieczeństwa, ponieważ adres URL może zostać zalogowany na serwerze, ujawniając poufne dane.
Ognyan
23

CustomRequest to sposób na rozwiązanie JSONObjectRequest Volleya nie może wysyłać parametrów, takich jak StringRequest

oto klasa pomocnicza, która pozwala na dodawanie parametrów:

    import java.io.UnsupportedEncodingException;
    import java.util.Map;    
    import org.json.JSONException;
    import org.json.JSONObject;    
    import com.android.volley.NetworkResponse;
    import com.android.volley.ParseError;
    import com.android.volley.Request;
    import com.android.volley.Response;
    import com.android.volley.Response.ErrorListener;
    import com.android.volley.Response.Listener;
    import com.android.volley.toolbox.HttpHeaderParser;

    public class CustomRequest extends Request<JSONObject> {

    private Listener<JSONObject> listener;
    private Map<String, String> params;

    public CustomRequest(String url, Map<String, String> params,
            Listener<JSONObject> reponseListener, ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        this.listener = reponseListener;
        this.params = params;
    }

    public CustomRequest(int method, String url, Map<String, String> params,
            Listener<JSONObject> reponseListener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.listener = reponseListener;
        this.params = params;
    }

    protected Map<String, String> getParams()
            throws com.android.volley.AuthFailureError {
        return params;
    };

    @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 e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }

    @Override
    protected void deliverResponse(JSONObject response) {
        // TODO Auto-generated method stub
        listener.onResponse(response);
    }

}

dzięki Greenchiu

LOG_TAG
źródło
@WarrenFaith Dzięki za zwrócenie uwagi, zaktualizowałem odpowiedź!
LOG_TAG
3
Wielkie dzięki, szukałem godzinami, zanim dostałem to rozwiązanie, to takie dziwne, że nadpisywanie getParams()funkcji JSONObjectReuqest nie działa.
Walid Ammar,
@MohammadWalid FYI przeczytaj ten stackoverflow.com/questions/16902716/ ... i spróbuj użyć modernizacji! zarówno volley, jak i retrofit mogą być używane z okhttp!
LOG_TAG
Wypróbowałem to rozwiązanie, ale nie zadziałało. getParams () nie jest wywoływana.
Mahdi
10

Ta klasa pomocnicza zarządza parametrami żądań GET i POST :

import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;    

import org.json.JSONException;
import org.json.JSONObject;

import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;

public class CustomRequest extends Request<JSONObject> {
    private int mMethod;
    private String mUrl;
    private Map<String, String> mParams;
    private Listener<JSONObject> mListener;

    public CustomRequest(int method, String url, Map<String, String> params,
            Listener<JSONObject> reponseListener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.mMethod = method;
        this.mUrl = url;
        this.mParams = params;
        this.mListener = reponseListener;
    }

@Override
public String getUrl() {
    if(mMethod == Request.Method.GET) {
        if(mParams != null) {
            StringBuilder stringBuilder = new StringBuilder(mUrl);
            Iterator<Map.Entry<String, String>> iterator = mParams.entrySet().iterator();
            int i = 1;
            while (iterator.hasNext()) {
                Map.Entry<String, String> entry = iterator.next();
                if (i == 1) {
                    stringBuilder.append("?" + entry.getKey() + "=" + entry.getValue());
                } else {
                    stringBuilder.append("&" + entry.getKey() + "=" + entry.getValue());
                }
                iterator.remove(); // avoids a ConcurrentModificationException
                i++;
            }
            mUrl = stringBuilder.toString();
        }
    }
    return mUrl;
}

    @Override
    protected Map<String, String> getParams()
            throws com.android.volley.AuthFailureError {
        return mParams;
    };

    @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 e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }

    @Override
    protected void deliverResponse(JSONObject response) {
        // TODO Auto-generated method stub
        mListener.onResponse(response);
    }
}
Andrea Motto
źródło
To rozwiązuje dodawanie parametrów do metody GET, dziękuję!
pkarc
2
W naszym przypadku iterator zniszczył oryginalny obiekt Map params, który przekazaliśmy do funkcji. Wygląda na to, że Volley dzwoni wewnętrznie GetUrlkilka razy. Skończyło się na klasycznym podejściu foreach opisanym w osobnej odpowiedzi. Mam nadzieję, że to pomoże temu, kto tu wyląduje. :)
Paolo Casciello
Jak wywołać tę klasę pomocniczą w celu uzyskania żądania z 3 parametrami
kgandroid
@kgandroid, utwórz Map <String, String> ze swoimi kluczami i wartościami. Przykład: Map <String, String> params = new HashMap <String, String> (); params.put ("param1", "wartość1"); params.put ("param2", "wartość2"); params.put ("param3", "wartość3");
Andrea Motto
6

Zajmując się parametrami GET iterowałem na rozwiązaniu Andrea Motto. Problem polegał na tym, że Volley dzwonił GetUrlkilka razy i jego rozwiązanie, używając Iteratora, zniszczyło oryginalny obiekt Map. Kolejne wywołania wewnętrzne Volley miały pusty obiekt params.

Dodałem też kodowanie parametrów.

Jest to użycie wbudowane (bez podklasy).

public void GET(String url, Map<String, String> params, Response.Listener<String> response_listener, Response.ErrorListener error_listener, String API_KEY, String stringRequestTag) {
    final Map<String, String> mParams = params;
    final String mAPI_KEY = API_KEY;
    final String mUrl = url;

    StringRequest stringRequest = new StringRequest(
            Request.Method.GET,
            mUrl,
            response_listener,
            error_listener
    ) {
        @Override
        protected Map<String, String> getParams() {
            return mParams;
        }

        @Override
        public String getUrl() {
            StringBuilder stringBuilder = new StringBuilder(mUrl);
            int i = 1;
            for (Map.Entry<String,String> entry: mParams.entrySet()) {
                String key;
                String value;
                try {
                    key = URLEncoder.encode(entry.getKey(), "UTF-8");
                    value = URLEncoder.encode(entry.getValue(), "UTF-8");
                    if(i == 1) {
                        stringBuilder.append("?" + key + "=" + value);
                    } else {
                        stringBuilder.append("&" + key + "=" + value);
                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                i++;

            }
            String url = stringBuilder.toString();

            return url;
        }

        @Override
        public Map<String, String> getHeaders() {
            Map<String, String> headers = new HashMap<>();
            if (!(mAPI_KEY.equals(""))) {
                headers.put("X-API-KEY", mAPI_KEY);
            }
            return headers;
        }
    };

    if (stringRequestTag != null) {
        stringRequest.setTag(stringRequestTag);
    }

    mRequestQueue.add(stringRequest);
}

Ta funkcja używa nagłówków do przekazania APIKEY i ustawia TAG na żądanie przydatne do anulowania go przed jego zakończeniem.

Mam nadzieję że to pomoże.

Paolo Casciello
źródło
3

To może ci pomóc ...

private void loggedInToMainPage(final String emailName, final String passwordName) {

    String tag_string_req = "req_login";
    StringRequest stringRequest = new StringRequest(Request.Method.POST, "http://localhost/index", new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            Log.d(TAG, "Login Response: " + response.toString());
            try {
                JSONObject jsonObject = new JSONObject(response);
                Boolean error = jsonObject.getBoolean("error");
                if (!error) {

                    String uid = jsonObject.getString("uid");
                    JSONObject user = jsonObject.getJSONObject("user");
                    String email = user.getString("email");
                    String password = user.getString("password");


                    session.setLogin(true);
                    Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                    startActivity(intent);
                    finish();
                    Toast.makeText(getApplicationContext(), "its ok", Toast.LENGTH_SHORT).show();
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            System.out.println("volley Error .................");
        }
    }) {
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> params = new HashMap<String, String>();
            params.put("tag", "login");
            params.put("email", emailName);
            params.put("password", passwordName);
            return params;
        }
    };


    MyApplication.getInstance().addToRequestQueue(stringRequest,tag_string_req);
}
Mahbod
źródło
3

Dla przyszłych czytelników

Uwielbiam pracować z Volley . Aby zaoszczędzić czas na rozwój, próbowałem napisać małą, poręczną bibliotekę Gloxey Netwok Manager, aby skonfigurować Volley z moim projektem. Zawiera parser JSON i różne inne metody, które pomagają sprawdzić dostępność sieci.

Użyj, ConnectionManager.classw którym dostępne są różne metody dla żądania Volley String i Volley JSON . Możesz wysyłać żądania GET, PUT, POST, DELETE z nagłówkiem lub bez. Możesz przeczytać pełną dokumentację tutaj .

Po prostu umieść tę linię w swoim pliku gradle.

  dependencies { 

       compile 'io.gloxey.gnm:network-manager:1.0.1'
   }

Volley StringRequest

Metoda GET (bez nagłówka)

    ConnectionManager.volleyStringRequest(context, isDialog, progressDialogView, requestURL, volleyResponseInterface);

Jak używać?

     Configuration                Description

     Context                      Context 
     isDialog                     If true dialog will appear, otherwise not.
     progressView                 For custom progress view supply your progress view id and make isDialog true. otherwise pass null. 
     requestURL                   Pass your API URL.  
     volleyResponseInterface      Callback for response.  

Przykład

    ConnectionManager.volleyStringRequest(this, false, null, "url", new VolleyResponse() {
    @Override
    public void onResponse(String _response) {

        /**
         * Handle Response
         */
    }

    @Override
     public void onErrorResponse(VolleyError error) {

        /**
         * handle Volley Error
         */
    }

    @Override
    public void isNetwork(boolean connected) {

        /**
         * True if internet is connected otherwise false
         */
    }
});

Volley StringRequest

Metoda POST / PUT / DELETE (bez nagłówka)

    ConnectionManager.volleyStringRequest(context, isDialog, progressDialogView, requestURL, requestMethod, params, volleyResponseInterface);

Przykład

Use Method : Request.Method.POST
             Request.Method.PUT
             Request.Method.DELETE

Your params : 

HashMap<String, String> params = new HashMap<>();
params.put("param 1", "value");
params.put("param 2", "value");

ConnectionManager.volleyStringRequest(this, true, null, "url", Request.Method.POST, params, new VolleyResponse() {
    @Override
    public void onResponse(String _response) {

        /**
         * Handle Response
         */
    }

    @Override
    public void onErrorResponse(VolleyError error) {

        /**
         * handle Volley Error
         */
    }

    @Override
    public void isNetwork(boolean connected) {

        /**
         * True if internet is connected otherwise false
         */
    }
});

Premia

Parser JSON Gloxey

Zachęcamy do używania parsera gloxey json do analizowania odpowiedzi interfejsu API.

  YourModel yourModel = GloxeyJsonParser.getInstance().parse(stringResponse, YourModel.class);

Przykład

ConnectionManager.volleyStringRequest(this, false, null, "url", new VolleyResponse() {
    @Override
    public void onResponse(String _response) {

        /**
         * Handle Response
         */

         try {

          YourModel yourModel = GloxeyJsonParser.getInstance().parse(_response, YourModel.class);

            } catch (Exception e) {
                e.printStackTrace();
            }

    }

    @Override
     public void onErrorResponse(VolleyError error) {

        /**
         * handle Volley Error
         */
         if (error instanceof TimeoutError || error instanceof NoConnectionError) {

                showSnackBar(parentLayout, getString(R.string.internet_not_found), getString(R.string.retry), new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {

                     //handle retry button

                    }
                });

            } else if (error instanceof AuthFailureError) {
            } else if (error instanceof ServerError) {
            } else if (error instanceof NetworkError) {
            } else if (error instanceof ParseError) {
            }

    }

    @Override
    public void isNetwork(boolean connected) {

        /**
         * True if internet is connected otherwise false
         */
          if (!connected) {
                showSnackBar(parentLayout, getString(R.string.internet_not_found), getString(R.string.retry), new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        //Handle retry button
                    }
                });
    }
});


     public void showSnackBar(View view, String message) {
            Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
     }

     public void showSnackBar(View view, String message, String actionText, View.OnClickListener onClickListener) {
            Snackbar.make(view, message, Snackbar.LENGTH_LONG).setAction(actionText, onClickListener).show();
     }
Adnan Bin Mustafa
źródło
Ale czy obsługuje Method.Get
David Kariuki
Tak, spójrz na szczegóły. github.com/adnanbinmustafa/Gloxey-Network-Manager
Adnan Bin Mustafa
0

Aby podać POSTparametr, wyślij parametr jak JSONObject w do JsonObjectRequestkonstruktora. Trzeci parametr akceptuje a, JSONObjectktóry jest używany w treści żądania.

JSONObject paramJson = new JSONObject();

paramJson.put("key1", "value1");
paramJson.put("key2", "value2");


JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,url,paramJson,
    new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {

        }
    },
    new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    });
requestQueue.add(jsonObjectRequest);
Abu Yousuf
źródło