Android Retrofit parametrizado @Headers

85

Estoy usando OAuth y necesito poner el token de OAuth en mi encabezado cada vez que hago una solicitud. Veo la @Headeranotación, pero ¿hay alguna manera de parametrizarla para que pueda pasar en tiempo de ejecución?

Aquí está el concepto

@Header({Authorization:'OAuth {var}', api_version={var} })

¿Puedes pasarlos en Runtime?

@GET("/users")
void getUsers(
    @Header("Authorization") String auth, 
    @Header("X-Api-Version") String version, 
    Callback<User> callback
)
jpotts18
fuente
¿Alguna vez resolviste esto? También necesito pasar un token en el encabezado
theSociableme
También estoy buscando una solución para esto, desde la documentación parece que la anotación @Headers () en el método agrega campos al encabezado uno por uno, pero solo admite literales. Y @Header ("parámetro") La anotación de parámetro de cadena de cadena reemplaza el encabezado con el valor proporcionado.
nana
2
Lo mismo aquí, no pude averiguar cómo manejar las sesiones cuando se usa la modificación.
FRR
No necesitábamos pasar todos los elementos, la retroadaptación se encargaba de todos. Consulte mi enlace de respuesta en StackOverflow.
Subin Babu

Respuestas:

98

Además de usar el parámetro @Header, prefiero usar RequestInterceptor para actualizar todas sus solicitudes sin cambiar su interfaz. Usando algo como:

RestAdapter.Builder builder = new RestAdapter.Builder()
    .setRequestInterceptor(new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            request.addHeader("Accept", "application/json;versions=1");
            if (isUserLoggedIn()) {
                request.addHeader("Authorization", getToken());
            }                    
        }
    });

p / s: si está usando Retrofit2, debe usar en Interceptorlugar deRequestInterceptor

Dado RequestInterceptorque ya no está disponible en Retrofit 2.0

Felix
fuente
3
Esto no está directamente relacionado, pero si necesita obtener valores del objeto de solicitud para generar su encabezado de autorización, deberá extender ApacheClient y ejecutar duplicar el objeto de solicitud (List <Header> header = ... ; Solicitud requestNew = nueva Solicitud (request.getMethod (), request.getUrl (), headers, request.getBody ()); request = requestNew).
1
Ese es un truco que estropea un código, mejor use la respuesta de @ nana
Ivan Fazaniuk
1
RestAdapterdepende de Retrofit1, en Retrofit2 lo es Retrofit. Voy a usar Retrofit2, por lo que no hay problemas si se usa RequestInterceptorcomo el código anterior.
Torre Huy
55

Sí, puede pasarlos en tiempo de ejecución. De hecho, casi exactamente como lo escribió. Esto estaría en su clase de interfaz API, llamada, por ejemplo, SecretApiInterface.java

public interface SecretApiInterface {

    @GET("/secret_things")
    SecretThing.List getSecretThings(@Header("Authorization") String token)

}

Luego, pasa los parámetros a esta interfaz desde su solicitud, algo así: (este archivo sería, por ejemplo, SecretThingRequest.java )

public class SecretThingRequest extends RetrofitSpiceRequest<SecretThing.List, SecretApiInteface>{

    private String token;

    public SecretThingRequest(String token) {
        super(SecretThing.List.class, SecretApiInterface.class);
        this.token = token;
    }

    @Override
    public SecretThing.List loadDataFromNetwork() {
        SecretApiInterface service = getService();
        return service.getSecretThings(Somehow.Magically.getToken());
    }
}

Dónde Somehow.Magically.getToken()hay una llamada a un método que devuelve un token, depende de usted dónde y cómo lo defina.

Por supuesto, puede tener más de una @Header("Blah") String blahanotación en la implementación de la interfaz, ¡como en su caso!

También lo encontré confuso, la documentación dice claramente que reemplaza el encabezado, ¡pero NO LO HACE !
De hecho, se agrega como con la @Headers("hardcoded_string_of_liited_use")anotación

Espero que esto ayude ;)

nana
fuente
1
Encontré en los documentos que no reemplaza un encabezado existente: "Tenga en cuenta que los encabezados no se sobrescriben entre sí". Compruebe square.github.io/retrofit y "Manipulación de encabezados"
Amio.io
37

La respuesta aceptada es para una versión anterior de Retrofit. Para los futuros espectadores, la forma de hacer esto con Retrofit2.0 es utilizando un cliente OkHttp personalizado:

OkHttpClient httpClient = new OkHttpClient.Builder()
  .addInterceptor(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
      Builder ongoing = chain.request().newBuilder();
      ongoing.addHeader("Accept", "application/json;versions=1");
      if (isUserLoggedIn()) {
        ongoing.addHeader("Authorization", getToken());
      }
      return chain.proceed(ongoing.build());
    }
  })
  .build();

Retrofit retrofit = new Retrofit.Builder()
  // ... extra config
  .client(httpClient)
  .build();

Espero que ayude a alguien. :)

pablisco
fuente
5
En el uso común con dagger2, retrofit2 será singleton, por lo tanto, httpclient no se creará cada vez. en ese caso isUserLoggedIn () no tiene sentido, ¿verdad? La única solución que puedo ver actualmente es forzar la reinicialización de retrofit2 cuando se cambia el estado de inicio de sesión del usuario, para que el encabezado apropiado se agregue o elimine de la solicitud ... ¿o hay alguna solución obvia que no puedo ver actualmente? Gracias.
bajicdusko
2
@bajicdusko, este es exactamente mi mismo acertijo. ¿Has encontrado una solución? Parece tan derrochador y extraño que la versión anterior fuera más eficiente.
deed02392
@ deed02392 Puede configurar un compuesto Interceptoral que puede configurar o restablecer el interceptor en una etapa posterior. Sin embargo, yo diría que tener una actualización como singleton puede ser una señal de optimización temprana. No hay gastos generales para crear una nueva instancia de actualización
pablisco
Realmente no lo pensé profundamente. Tengo una clase de ApiFactory que también se inicializa con dagger2, y es responsable de la inicialización de la modificación. He expuesto un método público en ApiFactory que fuerza la reinicialización de la instancia de actualización cuando es necesario, por lo que es bastante simple. Podría hacerlo mal, pero hizo el trabajo, y lo estoy usando solo para el encabezado de Autorización, por lo que se usa cuando el usuario inicia o cierra sesión. Otra opción es usar la anotación @Header dentro de la definición del punto final, lo cual no era aceptable para mí. Debería establecerlo en cada punto final, lo cual no es práctico.
bajicdusko
@pablisco Ah, según tengo entendido, no podría agregar ni eliminar correos electrónicos Interceptoruna vez que haya creado una instancia de Retrofit2.
deed02392
7

Modernización 2.3.0

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
    okHttpClientBuilder
            .addInterceptor(new Interceptor() {
                @Override
                public okhttp3.Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Request.Builder newRequest = request.newBuilder().header("Authorization", accessToken);
                    return chain.proceed(newRequest.build());
                }
            });

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(GithubService.BASE_URL)
            .client(okHttpClientBuilder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

Estoy usando esto para conectarme a GitHub.

Pronto Santos
fuente