Retrofit忽略查询参数

时间:2017-04-20 08:58:15

标签: android json gson retrofit

我正在尝试使用Retrofit和Gson解析JSON文件。问题是URL接受参数forceDeviceId。如果此值设置为-111,则可以检索正确的文件。默认情况下,此参数设置为-1并抛出404错误:

无效 https://www.mediamarkt.de/de/product/productlistajax.json?categoryId=563612&sort=topseller&lazyLoading=true&forceDeviceId=-1

工作 https://www.mediamarkt.de/de/product/productlistajax.json?categoryId=563612&sort=topseller&lazyLoading=true&forceDeviceId=-111

我尝试了两种方法:在API网址中对参数进行硬编码并使用查询:

// either hardcoded in the URL
@GET("de/product/productlistajax.json?forceDeviceId=-111")
  Call<ProductListParent> loadProductList(
        @Query("categoryId") String categoryId,
        @Query("sort") String sort,
        @Query("lazyLoading") String lazyLoading,
        // alternatively use this query
        @Query("forceDeviceId") String forceDeviceId
);

但是这两种方法都返回404.所以我想知道我缺少什么才能使它工作(就像在浏览器中一样)。我还认识到,在加载浏览器中的URL后,该参数将被删除immediatley。他们的后端会阻止这件事吗?

以下是我打电话的方法:

  @Subscribe
    public void getProductListRequest(MMSATServices.ProductListRequest request) {
        final MMSATServices.ProductListResponse productListResponse = new MMSATServices.ProductListResponse();
        productListResponse.productListParent = new ProductListParent();

        Call<ProductListParent> call = liveApi.loadProductList(
                request.categoryId, request.sort, request.lazyLoading, request.forceDeviceId);
        call.enqueue(new Callback<ProductListParent>() {
            @Override
            public void onResponse(Call<ProductListParent> call, Response<ProductListParent> response) {
                productListResponse.productListParent = response.body();
                bus.post(productListResponse);
            }

            @Override
            public void onFailure(Call<ProductListParent> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }

这是我收到的错误消息:

Response{protocol=http/1.1, code=404, message=Not Found, url=https://www.mediamarkt.de/de/product/productlistajax.json?categoryId=563612&sort=topseller&lazyLoading=true}

编辑:这是我创建Retrofit对象的方法

private static Retrofit createMMSATService(String baseUrl) {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .cookieJar(new CustomCookieJar())
            .build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    return retrofit;
}

使用CustomCookieJAr类:

public class CustomCookieJar implements CookieJar {

    private List<Cookie> cookies = new ArrayList<>();

    @Override
    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
        if (cookies != null) {
            this.cookies = cookies;
        }
    }

    @Override
    public List<Cookie> loadForRequest(HttpUrl url) {
        return cookies;
    }
}

3 个答案:

答案 0 :(得分:3)

执行此请求时附加2件事,首先获得302响应,然后OkHTTP在302请求提供的新位置执行请求。第二个请求因404响应而失败。我发现302回复标题中包含2个新Cookie:MC_DEVICE_IDMC_DEVICE_ID_EXT。所以我配置了OkHTTP(Retrofit使用的请求引擎)将302响应中收到的cookie发送到第二个请求,它就可以了!

这解释了为什么它在Web浏览器中工作,因为Web浏览器存储返回的cookie并再次发送它以用于第二个请求。默认情况下,OkHTTP没有此机制,您必须在新请求中手动设置302响应中的cookie。

有我的代码:

 Retrofit retrofit = new Retrofit.Builder()
            .client(new OkHttpClient.Builder()
                    .cookieJar(new CookieJar() {
                        private List<Cookie> cookies = new ArrayList<>();
                        @Override
                        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                            if (cookies != null) {
                                this.cookies = cookies;
                            }
                        }

                        @Override
                        public List<Cookie> loadForRequest(HttpUrl url) {
                            return cookies;
                        }
                    }).build())
            .baseUrl("https://www.mediamarkt.de/")
            .build()

以前的回答

即使我正在调试,Retrofit / OkHTTP堆栈跟踪也很难解码,但据我所知,网址https://www.mediamarkt.de/de/product/productlistajax.json?categoryId=563612&sort=topseller&lazyLoading=true&forceDeviceId=-111会返回302 http代码(暂时移动)并在响应头中返回新地址。

问题是标题location提供的网址不包含查询参数forceDeviceId。它是来自mediamarkt API的一个错误,我建议你向mediamarkt开发者报告这个错误,并找到另一种方式来发送这个参数(我不能帮助更多,我不明白德国语言)。

一些细节:

第一次调用时返回302的响应: Response{protocol=http/1.1, code=302, message=Found, url=https://www.mediamarkt.de/de/product/productlistajax.json?forceDeviceId=-111&categoryId=563612&sort=topseller&lazyLoading=true}

OkHTTP通过调用以下内容获取新位置:

String location = userResponse.header("Location");

(见RetryAndFollowUpInterceptor.java:301

location的值为/de/product/productlistajax.json?categoryId=563612&sort=topseller&lazyLoading=true。如您所见,缺少参数forceDeviceId:/

答案 1 :(得分:0)

您不需要在GET注释中包含查询参数。下面的代码对我来说很好

@GET("de/product/productlistajax.json")
Call<AppConfigParent> loadAppConfigParent(@Query("forceDeviceId") String forceDeviceId);

答案 2 :(得分:-1)

使用其他参数发送此参数

   // either hardcoded in the URL
@GET("de/product/productlistajax.json")
  Call<ProductListParent> loadProductList(
        @Query("forceDeviceId") String forceDeviceId,
        @Query("categoryId") String categoryId,
        @Query("sort") String sort,
        @Query("lazyLoading") String lazyLoading,
        // alternatively use this query
        @Query("forceDeviceId") String forceDeviceId
);