在 Retrofit 中发出 form-urlencoded Get 请求时,如何避免请求参数名称被编码?
How can I avoid request parameter names getting encoded when making a form-urlencoded Get request in Retrofit?
我目前正在开发 android 应用程序,该应用程序使用 Retrofit 和 OkHttpClient 从服务器获取 get/send 数据。
这在调用我自己的服务器时很棒,而在尝试调用 google map api.
时遇到 404 错误
以下表示有错误的响应。
响应{协议=h2,代码=404,消息=,url=<a href="https://maps.googleapis.com/maps%2Fapi%2Fgeocode%2Fjson%3Fkey=defesdvmdkeidm&latlng=11.586215,104.893197" rel="nofollow noreferrer">https://maps.googleapis.com/maps%2Fapi%2Fgeocode%2Fjson%3Fkey=defesdvmdkeidm&latlng=11.586215,104.893197</a>}
这显然是因为“/”和“?”被编码为“%2F”和“%3F”。
解决方案可以阻止 url 对这些特殊字符进行编码,但无法做到。
我尝试通过拦截器将自定义 header "Content-Type:application/x-www-form-urlencoded; charset=utf-8" 添加到 OkHttpClient,但这不起作用。
最详细的回复将不胜感激。
此致。
private Retrofit createRetrofit(OkHttpClient client, String _baseUrl) {
return new Retrofit.Builder()
.baseUrl(_baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
}
private Retrofit createGoogleRetrofit() {
return createRetrofit(createGoogleClient(), baseUrl);
}
public DenningService getGoogleService() {
_baseUrl = "https://maps.googleapis.com/";
final Retrofit retrofit = createGoogleRetrofit();
return retrofit.create(DenningService.class);
}
public interface DenningService {
@GET("{url}")
@Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Single getEncodedRequest(@Path("url") String url);
}
private void sendRequest(final CompositeCompletion completion, final ErrorHandler errorHandler) {
mCompositeDisposable.add(mSingle.
subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function() {
@Override
public JsonElement apply(JsonElement jsonElement) throws Exception {
return jsonElement;
}
})
.subscribeWith(new DisposableSingleObserver() {
@Override
public void onSuccess(JsonElement jsonElement) {
completion.parseResponse(jsonElement);
}
@Override
public void onError(Throwable e) {
if (e instanceof HttpException && ((HttpException) e).code() == 410) {
errorHandler.handleError("Session expired. Please log in again.");
} else {
errorHandler.handleError(e.getMessage());
}
e.printStackTrace();
}
})
);
}
public void sendGoogleGet(String url, final CompositeCompletion completion) {
mSingle = getGoogleService().getEncodedRequest(url);
sendRequest(completion, new ErrorHandler() {
@Override
public void handleError(String error) {
ErrorUtils.showError(context, error);
}
});
}
问题出在 Retrofit 服务接口的定义和传递给它的值上。
public interface DenningService {
@GET("{url}")
@Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Single getEncodedRequest(@Path("url") String url);
}
根据您发布的内容,我假设 url
的值为:
maps/api/geocode/json?key=defesdvmdkeidm&latlng=11.586215,104.893197
它应该是这样的:
public interface DenningService {
@FormUrlEncoded
@GET("/maps/api/geocode/json")
Single getEncodedRequest(@Field("key") String key,
@Field("latlng") String latlng);
}
然后你会这样称呼它:
mSingle = getGoogleService().getEncodedRequest(key, latlng);
当然,您必须弄清楚如何将 key
和 latlng
参数从当前 url
字符串中分离出来。
编辑
我不清楚你是否真的想要你的请求是application/x-www-form-urlencoded
,或者你只是想看看它是否解决了你的问题.如果您不想要它,那么您的界面将如下所示:
public interface DenningService {
@GET("/maps/api/geocode/json")
Single getEncodedRequest(@Query("key") String key,
@Query("latlng") String latlng);
}
我目前正在开发 android 应用程序,该应用程序使用 Retrofit 和 OkHttpClient 从服务器获取 get/send 数据。 这在调用我自己的服务器时很棒,而在尝试调用 google map api.
时遇到 404 错误以下表示有错误的响应。
响应{协议=h2,代码=404,消息=,url=<a href="https://maps.googleapis.com/maps%2Fapi%2Fgeocode%2Fjson%3Fkey=defesdvmdkeidm&latlng=11.586215,104.893197" rel="nofollow noreferrer">https://maps.googleapis.com/maps%2Fapi%2Fgeocode%2Fjson%3Fkey=defesdvmdkeidm&latlng=11.586215,104.893197</a>}
这显然是因为“/”和“?”被编码为“%2F”和“%3F”。 解决方案可以阻止 url 对这些特殊字符进行编码,但无法做到。
我尝试通过拦截器将自定义 header "Content-Type:application/x-www-form-urlencoded; charset=utf-8" 添加到 OkHttpClient,但这不起作用。
最详细的回复将不胜感激。
此致。
private Retrofit createRetrofit(OkHttpClient client, String _baseUrl) {
return new Retrofit.Builder()
.baseUrl(_baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
}
private Retrofit createGoogleRetrofit() {
return createRetrofit(createGoogleClient(), baseUrl);
}
public DenningService getGoogleService() {
_baseUrl = "https://maps.googleapis.com/";
final Retrofit retrofit = createGoogleRetrofit();
return retrofit.create(DenningService.class);
}
public interface DenningService {
@GET("{url}")
@Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Single getEncodedRequest(@Path("url") String url);
}
private void sendRequest(final CompositeCompletion completion, final ErrorHandler errorHandler) {
mCompositeDisposable.add(mSingle.
subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function() {
@Override
public JsonElement apply(JsonElement jsonElement) throws Exception {
return jsonElement;
}
})
.subscribeWith(new DisposableSingleObserver() {
@Override
public void onSuccess(JsonElement jsonElement) {
completion.parseResponse(jsonElement);
}
@Override
public void onError(Throwable e) {
if (e instanceof HttpException && ((HttpException) e).code() == 410) {
errorHandler.handleError("Session expired. Please log in again.");
} else {
errorHandler.handleError(e.getMessage());
}
e.printStackTrace();
}
})
);
}
public void sendGoogleGet(String url, final CompositeCompletion completion) {
mSingle = getGoogleService().getEncodedRequest(url);
sendRequest(completion, new ErrorHandler() {
@Override
public void handleError(String error) {
ErrorUtils.showError(context, error);
}
});
}
问题出在 Retrofit 服务接口的定义和传递给它的值上。
public interface DenningService { @GET("{url}") @Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8") Single getEncodedRequest(@Path("url") String url); }
根据您发布的内容,我假设 url
的值为:
maps/api/geocode/json?key=defesdvmdkeidm&latlng=11.586215,104.893197
它应该是这样的:
public interface DenningService {
@FormUrlEncoded
@GET("/maps/api/geocode/json")
Single getEncodedRequest(@Field("key") String key,
@Field("latlng") String latlng);
}
然后你会这样称呼它:
mSingle = getGoogleService().getEncodedRequest(key, latlng);
当然,您必须弄清楚如何将 key
和 latlng
参数从当前 url
字符串中分离出来。
编辑
我不清楚你是否真的想要你的请求是application/x-www-form-urlencoded
,或者你只是想看看它是否解决了你的问题.如果您不想要它,那么您的界面将如下所示:
public interface DenningService {
@GET("/maps/api/geocode/json")
Single getEncodedRequest(@Query("key") String key,
@Query("latlng") String latlng);
}