Volley - parámetros POST / GET

81

Vi la sesión de Google IO 2013 sobre Volley y estoy considerando cambiarme a voley. ¿Volley admite la adición de parámetros POST / GET a la solicitud? Si es así, ¿cómo puedo hacerlo?

Ziem
fuente
2
No vi la nota clave completa, pero estoy bastante seguro de que GET debería ser factible simplemente agregando los parámetros a la URL (por ejemplo http://example.com?param1=val1&param2=val2)
JJJollyjim
Parece que todavía no hay documentación, pero puede consultar la fuente aquí android.googlesource.com/platform/frameworks/volley/+/master
MM.
@ JJ56 - Correcto, pero ¿qué pasa con los parámetros POST? Vi el código fuente pero no encontré nada relacionado con los parámetros POST.
Ziem
1
Me da vergüenza decir esto. Pero, si llega aquí preguntando por qué su solicitud no tiene un cuerpo en su servidor, asegúrese de que está utilizando el método POST / PUT. Supongo que estoy cansado. Espero que este comentario ayude a alguien o me ayude a sentirme mejor
Alwin Kesler

Respuestas:

64

En su clase Request (que extiende Request), anule el método getParams (). Haría lo mismo con los encabezados, simplemente anule getHeaders ().

Si observa la clase PostWithBody en TestRequest.java en las pruebas de Volley, encontrará un ejemplo. Es algo parecido a esto

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 tuvo la amabilidad de hacer un proyecto de ejemplo rápido para mostrarnos cómo usar la volea. https://github.com/evancharlton/folly/

Afzal N
fuente
70
Tenga en cuenta que getParamssolo se llama (de forma predeterminada) en una solicitud POST o PUT, pero no en una solicitud GET. Vea la respuesta de Ogre_BGR
Itai Hanski
2
No puedo creer que nunca me di cuenta de eso hasta ahora
Afzal N
@AfzalivE, ¿alguna idea sobre cómo firmar una solicitud de API con OAuth cuando se usa el código anterior?
Bipin Vayalu
2
@BipinVayalu Si se está conectando a la API de Google, debería poder usar com.android.volley.AndroidAuthenticator
Pierre-Antoine
Olvidó crear una instancia de mParams.
Moritz
84

Para los parámetros GET hay dos alternativas:

Primero : como se sugiere en un comentario debajo de la pregunta, puede usar String y reemplazar los marcadores de posición de los parámetros con sus valores como:

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

donde num1 y num2 son variables de cadena que contienen sus valores.

Segundo : si está utilizando HttpClient externo más nuevo (4.2.x por ejemplo), puede usar URIBuilder para construir su Uri. La ventaja es que si su cadena uri ya tiene parámetros, será más fácil pasarla al URIBuildery luego usarla ub.setQuery(URLEncodedUtils.format(getGetParams(), "UTF-8"));para agregar sus parámetros adicionales. De esa forma, no se molestará en comprobar si "?" ya se ha agregado a la uri o se pierde alguno y, por lo tanto, elimina una fuente de posibles errores.

Para los parámetros POST, probablemente a veces será más fácil que la respuesta aceptada hacerlo como:

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

por ejemplo, para anular el getParams()método.

Puede encontrar un ejemplo funcional (junto con muchos otros ejemplos básicos de Volley) en el proyecto Andorid Volley Examples .

Ognyan
fuente
He seguido tus ejemplos de Volley. Hasta ahora, es el código Volly más útil, pero tengo problemas en JsonObjectRequest. Obtuve la respuesta anterior en createMyReqSuccessListener hasta que la reinstale nuevamente. ¿Volley almacena datos en caché? Sugiera una forma de hacer esto.
SkyWalker
2
Solo se almacenan en caché las imágenes. Compruebe si hay algún proxy que esté interceptando sus solicitudes. Si las solicitudes tienen exactamente la misma URL y es posible que el proxy simplemente devuelva el primer resultado.
Ognyan
2
Hay un complemento para Firefox llamado "prueba de recursos HTTP" que le permite enviar solicitudes contra el servidor web. Es muy útil para probar casos como este. Simplemente ingrese su URL (y los parámetros POST si los hay) y vea cuál es la respuesta del servidor para múltiples solicitudes consecutivas. Si de nuevo obtiene la misma respuesta, lo más probable es que el resultado se almacene en caché. En ese caso, puede examinar los encabezados devueltos para verificar si hay encabezados de proxy. Acerca de "no-cache": sí, debería funcionar.
Ognyan
2
Le sugiero que abra una pregunta separada para que otros puedan unirse y ayudar. Proporcione información sobre qué pila está usando HURL o HttpClient, también la versión de Android con la que está probando. Por favor, coloque un enlace a la nueva pregunta aquí para que la gente pueda seguir la discusión.
Ognyan
3
@Yousif Probablemente obtendrá respuestas mucho mejores si hace esto como una nueva pregunta, pero en resumen: la solicitud POST le permite enviar archivos y otros datos más grandes que no encajarán en la solicitud GET. Además, existe un riesgo de seguridad al utilizar la solicitud GET porque la URL puede registrarse en el servidor, exponiendo así datos confidenciales.
Ognyan
23

CustomRequest es una forma de resolver JSONObjectRequest de Volley no puede publicar parámetros como el StringRequest

aquí está la clase auxiliar que permite agregar parámetros:

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

}

gracias a Greenchiu

LOG_TAG
fuente
@WarrenFaith Gracias por señalar, ¡he actualizado la respuesta!
LOG_TAG
3
Muchas gracias, estuve buscando durante horas antes de obtener esta solución. Es tan extraño que la anulación de la getParams()función JSONObjectReuqest no funcione.
Walid Ammar
@MohammadWalid FYI leí esto stackoverflow.com/questions/16902716/… ¡ e intente usar la actualización! tanto la volea como la modernización se pueden utilizar con okhttp!
LOG_TAG
Probé esta solución, pero no funcionó para mí. getParams () no se llama.
Mahdi
10

Esta clase auxiliar administra los parámetros para las solicitudes GET y 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 Lema
fuente
Esto resuelve agregar parámetros al método GET, ¡Gracias!
pkarc
2
En nuestro caso, el enfoque del iterador destruyó el objeto Map params original que pasamos a la función. Parece que Volley llama internamente GetUrlvarias veces. Terminamos con un enfoque clásico de foreach según lo publicado en una respuesta separada. Espero que esto ayude a quien aterriza aquí. :)
Paolo Casciello
Cómo llamar a esta clase auxiliar para obtener una solicitud con 3 parámetros
kgandroid
@kgandroid, cree un mapa <String, String> con sus claves y valores. Ejemplo: Map <String, String> params = new HashMap <String, String> (); params.put ("param1", "valor1"); params.put ("param2", "valor2"); params.put ("param3", "valor3");
Andrea Lema
6

Al tratar con los parámetros GET , repetí la solución de Andrea Motto. El problema fue que Volley llamó GetUrlvarias veces y su solución, usando un iterador, destruyó el objeto Map original. Las siguientes llamadas internas de Volley tenían un objeto params vacío.

Agregué también la codificación de parámetros.

Este es un uso en línea (sin subclase).

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

Esta función usa encabezados para pasar una APIKEY y establece un TAG a la solicitud útil para cancelarla antes de que se complete.

Espero que esto ayude.

Paolo Casciello
fuente
3

Esto puede ayudarte ...

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
fuente
3

Para futuros lectores

Me encanta trabajar con Volley . Para ahorrar tiempo de desarrollo, traté de escribir una pequeña biblioteca práctica Gloxey Netwok Manager para configurar Volley con mi proyecto. Incluye un analizador JSON y otros métodos diferentes que ayudan a verificar la disponibilidad de la red.

Uso ConnectionManager.classen el que están disponibles diferentes métodos para la solicitud Volley String y Volley JSON . Puede realizar solicitudes de GET, PUT, POST, DELETE con o sin encabezado. Puedes leer la documentación completa aquí .

Simplemente coloque esta línea en su archivo gradle.

  dependencies { 

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

Volley StringRequest

Método GET (sin encabezado)

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

¿Cómo utilizar?

     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.  

Ejemplo

    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

Método POST / PUT / DELETE (sin encabezado)

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

Ejemplo

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
         */
    }
});

Prima

Analizador JSON Gloxey

Siéntase libre de usar el analizador json de gloxey para analizar su respuesta api.

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

Ejemplo

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
fuente
Pero, ¿es compatible con Method.Get
David Kariuki
Sí, por favor busque los detalles. github.com/adnanbinmustafa/Gloxey-Network-Manager
Adnan Bin Mustafa
0

Para proporcionar un POSTparámetro, envíe su parámetro como JSONObject en el JsonObjectRequestconstructor. El tercer parámetro acepta un JSONObjectque se usa en el cuerpo de la solicitud.

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
fuente