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

当然,您必须弄清楚如何将 keylatlng 参数从当前 url 字符串中分离出来。

编辑

我不清楚你是否真的想要你的请求是application/x-www-form-urlencoded,或者你只是想看看它是否解决了你的问题.如果您想要它,那么您的界面将如下所示:

public interface DenningService {
    @GET("/maps/api/geocode/json")
    Single getEncodedRequest(@Query("key") String key,
                             @Query("latlng") String latlng);
}