2015-10-19 13 views
15

Ging auf Upgrade auf Retrofit 2.0 und läuft in dieses seltsame Problem.Retrofit 2.0-beta-2 fügt literalen Anführungszeichen zu MultiPart-Werten hinzu

habe ich eine Methode einen Benutzer in

public interface ApiInterface { 

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

Wenn ich an dem Schlüsselwert POST params auf der Server-Seite schauen, um ProtDruck sie wie diese

username : "brian" 
password : "password" 

mit der gleichen Methode Retrofit 1.9 die K: V-Paare sehen aus wie

username : brian 
password : password 

Es wörtliche Zitate zu den POST-Variablen Hinzufügen

Wenn ich einen anderen Restclient verwende, werden die Variablen wie die zweite Möglichkeit ohne die Anführungszeichen gedruckt.

Hier ist, wie ich die Retrofit-Instanz mit einem Interceptor bauen

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

Ich stelle mir vor, ich bin etwas falsch mit dem Konverter zu tun, aber nicht sicher, was.

Ist noch jemand in dieses Problem geraten? Ich weiß es in der Beta, aber es ist ziemlich widly verwendet.

+1

Exakt gleich hier. Ich habe gerade ein 2-Tage-Upgrade von Retrofit 2.0 abgeschlossen, die meisten Dinge funktionieren perfekt, aber ich bin verrückt nach diesen zusätzlichen Anführungszeichen, die den Strings hinzugefügt wurden. Mit einer '' @ @ Multipart''' Retrofit API-Methode ist string ein '' '@ Part''-Element. Der Server erhält die Zeichenfolge "test" als "" test "". PFUI!!! –

+0

@MatthewHousser Ich habe noch keine echte Lösung gefunden, da ich nun auch die Kontrolle über das Backend habe, habe ich einen speziellen Header in der Client-App gesetzt, und wenn dieser Header existiert, führe ich eine Methode aus, die die Anführungszeichen von GET und POST entfernt , es ist super hacky, aber wenigstens funktionieren die Anfragen jetzt. Ich denke, ich werde ein Problem auf der Github Repo – Brian

+0

öffnen Sie bitte Ihr Problem hier, nachdem Sie es erstellen, danke! –

Antwort

2

Was ist auf diese Weise zu tun?

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

Hier ist, wie es zu lösen,

Erstens:

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

erstellen CustomConverter wie dieses, das durch Retrofit benötigt wird 2, es sei denn, einige der "Feature" fixieren hinzugefügt 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

Dies ist, weil es durch den JSON-Konverter läuft.

Solution1: Verwendung RequestBody statt String

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

Körperbau RequestBody:

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

Starten Netzbetrieb:

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

Solution2: Erstellen Sie eine benutzerdefinierte ConverterFactory, um den String-Part-Wert zu entfernen.

Für: Retrofit2 endgültige Version nicht Beta. (com.squareup.retrofit2: Nachrüstung: 2.0.0)

Erstellen Sie Ihre 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; 
} 

} 

auf Ihre Retrofit Instanz hinzufügen:

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

Achtung:StringConverterFactory sollte vor GsonConverterFactory hinzuzufügen!

dann können Sie String als Teilwert direkt verwenden.

Sie können in mehr Informationen zu diesem Thema finden https://github.com/square/retrofit/issues/1210

+1

Warum? diese "Solution2" verpflichtet sich nicht zu Retrofit? Ich benutze Retrofit: 2.0.2 und nur diese Antwort behebt das Problem, während es einige Lösungen gibt, die nicht funktioniert haben. –

+0

@JanakaRRajapaksha Wie Jake Wharton sagte: "Ich bin mir nicht sicher, ob ich es hinzufügen möchte". Beweis: https: //github.com/square/retrofit/issues/1210 – Yazon2006

0

Wenn Ihr UI Ihre Antworten mit Zitaten zeigt, können Sie getAsString statt toString

3

Ich habe eine andere außer those eine Lösung gefunden verwenden. Arbeitete mit Retrofit 2.1.0. (Rx-Adapter ist hier optional)

Meine Retrofit-Schnittstelle sieht wie folgt aus:

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

Und in ApiManager ich es wie folgt verwendet werden:

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

Es ist ähnlich von Loyea Solution1 aber ich denke, dass es ein wenig eleganter ist.

0

Ich weiß nicht, ob es zu spät ist, aber wir können auch Anfragen mit RequestBody senden.

Beispiel:

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

Wir können wie unten konvertieren:

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

Ich habe das gleiche Problem, und wie es gelöst:

1) In den build.gradle :

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

2) Fügen Sie hier eine Zeile hinzu:

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