我正在尝试将以下java模型发送为表单编码正文 WITHOUT 包装{}
。我已经尝试了一些我能找到的模型 NOT 作为JSON,但使用Retrofit 2作为表格编码数据。
// Sends as JSON
@Headers("Content-Type:application/x-www-form-urlencoded")
@POST(SERVICES + USERS)
Observable<UserInfoResponse> signupUser(@Body SignUpParams params);
// Works
@FormUrlEncoded
@POST(SERVICES + USERS)
Observable<UserInfoResponse> signupUser(
@Field("approve") boolean approve,
@Field("daily_newsletter") int newsletter,
@Field("include_order_info") boolean includeOrderInfo,
@Field("is_21") int is21,
@Field("is_guest") int isGuest,
@Field("method") String method,
@Field("email") String email,
@Field("password") String password,
@Field("oauth_token") String oauthToken
);
如果有帮助,这是我们的设置
// Dagger Provider
@Provides
@Singleton
@Named(JT_API)
Retrofit provideJTSecureApiRetrofit(OkHttpClient okHttpClient, Gson gson) {
Retrofit retrofit = new Retrofit.Builder().client(okHttpClient)
.baseUrl(jtBaseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit;
}
@Provides
@Singleton
OkHttpClient provideOkHttpClient(JTApp app) {
Interceptor addUrlParams = chain -> {
Request request = chain.request();
HttpUrl url = request.url()
.newBuilder()
.addQueryParameter("app_version", BuildConfig.VERSION_NAME)
.build();
request = request.newBuilder()
.url(url)
.build();
return chain.proceed(request);
};
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(addUrlParams);
// this doesn't seem to do anything…
okHttpClientBuilder.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.addHeader("Content-Type", "application/x-www-form-urlencoded");
Request request = requestBuilder.build();
return chain.proceed(request);
});
okHttpClientBuilder.readTimeout(JTApp.HTTP_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(JTApp.HTTP_TIMEOUT, TimeUnit.SECONDS);
return okHttpClientBuilder.build();
}
答案 0 :(得分:0)
如果我没弄错的话
对于application / x-www-form-urlencoded,HTTP消息的正文 发送到服务器本质上是一个巨大的查询字符串 - 名称/值 对由&符号(&amp;)分隔,名称与之分开 等于符号(=)的值。
答案 1 :(得分:0)
原来我必须创建自己的键值对转换器,它扩展了Retrofit2 Converter.Factory
/**
* Retrofit 2 Key Value Pair Form Data Encoder
*
* This is a copy over of {@link GsonConverterFactory}. This class sends the outgoing response as
* form data vs the gson converter which sends it as JSON. The response is proxied through the
* gson converter factory just the same though
*
* Created by marius on 11/17/16.
*/
public class RF2_KeyValuePairConverter extends Converter.Factory {
private final GsonConverterFactory gsonConverter;
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to form data and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static RF2_KeyValuePairConverter create() {
return create(new Gson());
}
/**
* Create an instance using {@code gson} for conversion. Encoding to Form data and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static RF2_KeyValuePairConverter create(Gson gson) {
return new RF2_KeyValuePairConverter(gson);
}
private final Gson gson;
private RF2_KeyValuePairConverter(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
this.gsonConverter = GsonConverterFactory.create(gson);
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return gsonConverter.responseBodyConverter(type, annotations, retrofit);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return new KeyValueBodyConverter<>(gson);
}
}
这是我们的KeyValueBody
public class KeyValuePairConverter extends retrofit2.Converter.Factory implements Converter {
private final Gson gson;
public KeyValuePairConverter(Gson gson) {
this.gson = gson;
}
// Taken from retrofit's GsonConverter
@Override
public Object fromBody(TypedInput body, Type type) throws ConversionException {
String charset = MimeUtil.parseCharset(body.mimeType());
InputStreamReader isr = null;
try {
isr = new InputStreamReader(body.in(), charset);
return gson.fromJson(isr, type);
} catch (IOException e) {
throw new ConversionException(e);
} catch (JsonParseException e) {
throw new ConversionException(e);
} finally {
if (isr != null) {
try {
isr.close();
} catch (IOException ignored) {
}
}
}
}
@Override
public TypedOutput toBody(Object object) {
String json = gson.toJson(object);
//Log.d( "RETROFIT", json );
Type type = new TypeToken<Map<String, Object>>() { } .getType();
// this converts any int values to doubles so we are fixing them back in pojoToTypedOutput
Map<String, Object> map = gson.fromJson(json, type);
String body = pojoToTypedOutput(map, null);
// removes the initial ampersand
return new TypedString(body.substring(1));
}
/**
* Converts object to list of query parameters
* (works with nested objects)
*
* @todo
* query parameter encoding
*
* @param map this is the object map
* @param parentKey this is the parent key for lists/arrays
* @return
*/
public String pojoToTypedOutput(Map<String, Object> map, String parentKey) {
StringBuffer sb = new StringBuffer();
if (map != null && map.size() > 0) {
for (String key : map.keySet()) {
// recursive call for nested objects
if (map.get(key).getClass().equals(LinkedTreeMap.class)) {
sb.append(pojoToTypedOutput((Map<String, Object>) map.get(key), key));
} else {
// parent key for nested objects
Object objectValue = map.get(key);
// converts any doubles that really could be ints to integers (0.0 to 0)
if (objectValue.getClass().equals(Double.class)) {
Double doubleValue = (Double) objectValue;
if ((doubleValue == Math.floor(doubleValue)) && !Double.isInfinite(doubleValue)) {
objectValue = ((Double) objectValue).intValue();
}
}
if (parentKey != null && parentKey.length() != 0) {
sb.append("&").append(key).append("=").append(objectValue);
} else {
sb.append("&").append(parentKey + "[" + key + "]").append("=").append(objectValue);
}
}
}
}
return sb.toString();
}
}
在您的“改造”构建器中添加.addConverterFactory(RF2_KeyValuePairConverter.create(gson))
,这会将您的回复转换为键/值对