2015-10-19 25 views
15

È passato all'aggiornamento a Retrofit 2.0 e si è imbattuto in questo strano problema.Retrofit 2.0-beta-2 aggiunge le virgolette letterali ai valori MultiPart

Ho un metodo per accedere un utente in

public interface ApiInterface { 

    @Multipart 
    @POST("user/login/") 
    Call<SessionToken> userLogin(@Part("username") String username, @Part("password") String password); 
} 

Quando guardo la chiave params valore post sul lato server stampano come questo

username : "brian" 
password : "password" 

Lo stesso metodo che utilizza retrofit 1.9 i K: coppie V sembrano

username : brian 
password : password 

E 'l'aggiunta di citazioni letterali alle variabili POST

Se utilizzo qualsiasi altro client di riposo, le variabili vengono stampate come la seconda modalità senza le virgolette.

Ecco come costruisco l'istanza Retrofit con un intercettore

OkHttpClient client = new OkHttpClient(); 
    client.interceptors().add(new Interceptor() { 
     @Override 
     public Response intercept(Chain chain) throws IOException { 
      Request original = chain.request(); 

      // Customize the request 
      Request request = original.newBuilder() 
        .header("Accept", "application/json") 
        .header("Authorization", myPrefs.accessToken().getOr("")) 
        .method(original.method(), original.body()) 
        .build(); 

      Response response = chain.proceed(request); 

      // Customize or return the response 
      return response; 
     } 
    }); 

    Ok2Curl.set(client); 

    Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl(apiEndpoint) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .client(client) 
      .build(); 

immagino che sto facendo qualcosa di sbagliato con il convertitore, ma non è sicuro che cosa.

Qualcun altro ha già riscontrato questo problema? So che è in beta, ma è ampiamente usato.

+1

Esattamente lo stesso qui. Ho appena terminato un massiccio aggiornamento di 2 giorni con Retrofit 2.0, la maggior parte delle cose funziona perfettamente, ma sto impazzendo con queste citazioni aggiuntive aggiunte alle stringhe. Usando un metodo API "Retrofit" '' '@ Multipart''', la stringa è un elemento' '' @ Part'''. Il server riceve la stringa "test" come "" test "". UGH !!! –

+0

@MatthewHousser Non ho ancora trovato una soluzione reale, dal momento che ho il controllo sul backend e ho impostato un'intestazione speciale nell'app client, quindi se questa intestazione esiste eseguo un metodo che rimuove le virgolette dai parametri GET e POST , è super hacky ma almeno le richieste funzionano per ora. Penso che aprirò un problema sul repository github – Brian

+0

per favore pubblica il tuo problema qui dopo averlo creato, grazie! –

risposta

2

Che ne dici di fare in questo modo?

RequestBody caption = RequestBody.create(MediaType.parse("text/plain"), new String("caption")); 
2

Ecco come risolverlo,

In primo luogo:

return new Retrofit.Builder() 
    .baseUrl(Env.GetApiBaseUrl()) 
    .addConverterFactory(new GsonStringConverterFactory()) 
    .addConverterFactory(GsonConverterFactory.create(gson)) 
    .client(getHttpClient()) 
    .build(); 

Creare un CustomConverter come questo, questo è necessario per Retrofit 2, a meno che qualche fissare la "caratteristica", ha aggiunto in v2.

public class GsonStringConverterFactory extends Converter.Factory { 
    private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain"); 

    @Override 
    public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) { 
     if (String.class.equals(type))// || (type instanceof Class && ((Class<?>) type).isEnum())) 
     { 
      return new Converter<String, RequestBody>() { 
       @Override 
       public RequestBody convert(String value) throws IOException { 
        return RequestBody.create(MEDIA_TYPE, value); 
       } 
      }; 
     } 
     return null; 
    } 
} 
20

Questo perché sta eseguendo il convertitore JSON.

Soluzione1: uso RequestBody invece di String

public interface ApiInterface { 
    @Multipart 
    @POST("user/login/") 
    Call<SessionToken> userLogin(@Part("username") RequestBody username, @Part("password") RequestBody password); 
} 

Corporatura RequestBody:

RequestBody usernameBody = RequestBody.create(MediaType.parse("text/plain"), usernameStr); 
RequestBody passwordBody = RequestBody.create(MediaType.parse("text/plain"), passwordStr); 

il funzionamento della rete di lancio:

retrofit.create(ApiInterface.class).userLogin(usernameBody , passwordBody).enqueue().... 

Soluzione2: Creare una ConverterFactory personalizzata per disporre il valore della parte String.

Per: Retrofit2 versione finale non beta. (Com.squareup.retrofit2: retrofit: 2.0.0)

Creare la StringConverterFactory:

public class StringConverterFactory extends Converter.Factory { 
private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain"); 

public static StringConverterFactory create() { 
    return new StringConverterFactory(); 
} 

@Override 
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { 
    if (String.class.equals(type)) { 
     return new Converter<ResponseBody, String>() { 

      @Override 
      public String convert(ResponseBody value) throws IOException { 
       return value.string(); 
      } 
     }; 
    } 
    return null; 
} 

@Override 
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { 
    if(String.class.equals(type)) { 
     return new Converter<String, RequestBody>() { 
      @Override 
      public RequestBody convert(String value) throws IOException { 
       return RequestBody.create(MEDIA_TYPE, value); 
      } 
     }; 
    } 

    return null; 
} 

} 

Aggiungi all'istanza retrofit:

retrofit = new Retrofit.Builder() 
      .baseUrl(SERVER_URL) 
      .client(client) 
      .addConverterFactory(StringConverterFactory.create()) 
      .addConverterFactory(GsonConverterFactory.create()) 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
      .build(); 

Attenzione:StringConverterFactory dovrebbe aggiungere prima GsonConverterFactory!

quindi è possibile utilizzare direttamente String come valore della parte.

Potete trovare ulteriori informazioni su questo problema in https://github.com/square/retrofit/issues/1210

+1

Perché questa "Soluzione2" non si impegna in Retrofit? Io uso Retrofit: 2.0.2 e solo questa risposta ha risolto il problema mentre ci sono poche soluzioni che non hanno funzionato. –

+0

@JanakaRRajapaksha Come ha detto Jake Wharton: "Non sono sicuro di volerlo aggiungere". Dimostrazione: https: //github.com/square/retrofit/issues/1210 – Yazon2006

0

Se la vostra interfaccia utente sta mostrando le tue risposte con le citazioni, è possibile utilizzare al posto di getAsStringtoString

3

ho trovato un'altra soluzione se those. Ha funzionato con Retrofit 2.1.0. (Adattatore Rx è facoltativo qui)

mia interfaccia retrofit si presenta così:

@POST("/children/add") 
Observable<Child> addChild(@Body RequestBody requestBody); 

E in ApiManager lo uso così:

@Override 
    public Observable<Child> addChild(String firstName, String lastName, Long birthDate, @Nullable File passportPicture) { 
     MultipartBody.Builder builder = new MultipartBody.Builder() 
       .setType(MultipartBody.FORM) 
       .addFormDataPart("first_name", firstName) 
       .addFormDataPart("last_name", lastName) 
       .addFormDataPart("birth_date", birthDate + ""); 

     //some nullable optional parameter 
     if (passportPicture != null) { 
      builder.addFormDataPart("certificate", passportPicture.getName(), RequestBody.create(MediaType.parse("image/*"), passportPicture)); 
     } 
     return api.addChild(builder.build()); 
    } 

E 'simile a Soluzione1 da Loyea ma io pensa che sia un po 'più elegante.

0

Non so se è troppo tardi, ma possiamo anche inviare richieste con RequestBody.

Esempio:

public interface ApiInterface { 
    @Multipart 
    @POST("user/login/") 
    Call<SessionToken> userLogin(@Part("username") String username, @Part("password") String password); 
} 

Siamo in grado di convertire, come di seguito:

public interface ApiInterface { 
    @Multipart 
    @POST("user/login/") 
    Call<SessionToken> userLogin(@Part("username") RequestBody username, @Part("password") String password); 
} 
0

Ho lo stesso problema, e come ha risolto:

1) Aggiungere alla build.gradle :

compile 'com.squareup.retrofit2:converter-scalars:2.1.0' // remeber add the same version 

2) Aggiungi una riga qui:

Retrofit retrofit = new Retrofit.Builder() 
       .baseUrl(URL_BASE) 
       .addConverterFactory(ScalarsConverterFactory.create()) // this line 
       .addConverterFactory(GsonConverterFactory.create(gson)) 
       .client(getUnsafeOkHttpClient()) 
       .build();