1
votes

I am currently developing android app which uses Retrofit & OkHttpClient to get/send data from the server. That was great when calling my own server, while it runs into 404 error when trying to call google map api.

The following represents response with error. Response{protocol=h2, code=404, message=, url=https://maps.googleapis.com/maps%2Fapi%2Fgeocode%2Fjson%3Fkey=defesdvmdkeidm&latlng=11.586215,104.893197}

This is obviously because '/' and '?' was encoded into "%2F" and "%3F". The solution could be prevent urlencode for those special characters, but couldn't make it.

What I tried is add custom header "Content-Type:application/x-www-form-urlencoded; charset=utf-8" to OkHttpClient via intercepter but that does not work.

Best detailed response will be appreciated.

Regards.



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

1
Could you post your retrofit service interface? - Ben P.
Ok. sorry for the late response. - David
I updated the question - David

1 Answers

0
votes

The problem is in the definition of your Retrofit service interface and the values you pass to it.

public interface DenningService {
    @GET("{url}")
    @Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
    Single getEncodedRequest(@Path("url") String url);
}

From what you've posted, I'm going to assume the value of url is:

maps/api/geocode/json?key=defesdvmdkeidm&latlng=11.586215,104.893197

Here's how it should look:

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

And then you'd call it like this:

mSingle = getGoogleService().getEncodedRequest(key, latlng);

Of course, you will have to figure out how to separate the key and latlng parameters out of the current url string.

Edit

It's not obvious to me whether or not you actually want your request to be application/x-www-form-urlencoded, or if you were just trying that to see if it solved your problem. If you do not want it, then your interface would look like this instead:

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