Android Retrofit2 reddit 404 未找到

Posted

技术标签:

【中文标题】Android Retrofit2 reddit 404 未找到【英文标题】:Android Retrofit2 reddit 404 Not Found 【发布时间】:2017-02-24 17:38:53 【问题描述】:

我正在使用改造为 Reddit 创建一个 android 客户端。 在 logcat 获取令牌工作正常,但是当我尝试获取登录用户的信息时,我得到“404 Not Found”。 这是我的日志:

D/OkHttp: --> POST https://oauth.reddit.com/api/v1/me http/1.1
D/OkHttp: Content-Length: 0
D/OkHttp: Authorization: bearer myToken
D/OkHttp: User-Agent: MyRedditClient/0.1 by myusername
D/OkHttp: --> END POST
D/OkHttp: <-- 404 Not Found https://oauth.reddit.com/api/v1/me (677ms)

这是我的代码:

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ServiceAuthGenerator 

    public static final String API_BASE_URL = "https://www.reddit.com/";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    public static <S> S getTokenService(Class<S> serviceClass) 
        return getTokenService(serviceClass, null, null);
    

    public static <S> S getTokenService(Class<S> serviceClass, String username, String password) 
        if (username != null && password != null) 
            String credentials = username + ":" + password;
            final String basic =
                    "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

            httpClient.addInterceptor(new Interceptor() 
                @Override
                public Response intercept(Interceptor.Chain chain) throws IOException 
                    Request original = chain.request();

                    Request.Builder requestBuilder = original.newBuilder()
                            .header("Authorization", basic)
                            .header("Accept", "application/json")
                            .method(original.method(), original.body());

                    Request request = requestBuilder.build();
                    return chain.proceed(request);
                
            );
        

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        OkHttpClient client = httpClient.addInterceptor(interceptor).build();
        Retrofit retrofit = builder.client(client).build();
        return retrofit.create(serviceClass);
    



import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ServiceInfoGenerator 

    public static final String API_BASE_URL = "https://oauth.reddit.com/";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    public static <S> S retrieveInfoService(Class<S> serviceClass) 
        return retrieveInfoService(serviceClass, null, null);
    

    public static <S> S retrieveInfoService(Class<S> serviceClass, final String authToken, final String username) 
        if (authToken != null && username != null) 
            httpClient.addInterceptor(new Interceptor() 
                @Override
                public Response intercept(Chain chain) throws IOException 
                    Request original = chain.request();

                    // Request customization: add request headers
                    Request.Builder requestBuilder = original.newBuilder()
                            .header("Authorization", " bearer "+authToken)
                            .header("User-Agent", "MyRedditClient/0.1 by "+username)
                            .method(original.method(), original.body());

                    Request request = requestBuilder.build();
                    return chain.proceed(request);
                
            );
        

        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

        OkHttpClient client = httpClient.addInterceptor(interceptor).build();
        try 
            client.interceptors().add(new UserAgentInterceptor(username));
         catch (Exception e)
            Log.i("ServiceInfoGenerator", "retrieveInfoService: "+e.getMessage());
        
        Retrofit retrofit = builder.client(client).build();
        return retrofit.create(serviceClass);
    


import java.util.Map;

import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.QueryMap;

public interface MyApiRetrofit 

    @POST("/api/v1/access_token")
    @FormUrlEncoded
    Call<Authorize> accessToken(@Field(("grant_type")) String grantType, @Field(("username")) String username, @Field(("password")) String password);

    @POST("/api/v1/me")
    Call<Authorize> retrieveMyInfo();



import android.os.AsyncTask;
import android.util.Log;

import com.havistudio.myreddit.api.Authorize;
import com.havistudio.myreddit.api.MyApiRetrofit;

import java.io.IOException;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class TestAPITask2 extends AsyncTask<Void, Void, Void> 

    private static final String TAG = "TestAPITask2";
    private String myAccessToken;
    private String myRefreshToken;

    @Override
    protected Void doInBackground(Void... voids) 

        MyApiRetrofit loginService = ServiceAuthGenerator.getTokenService(MyApiRetrofit.class, "client_id", "client_secret");
        Call<Authorize> call = loginService.accessToken("password", "myusername", "mypassword");
        call.enqueue(new Callback<Authorize>() 
            @Override
            public void onResponse(Call<Authorize> call, Response<Authorize> response) 
                if (response.isSuccessful()) 
                    // user object available
                    Log.i(TAG, "isSuccessful");
                    Authorize temp = response.body();
                    myAccessToken = temp.getAccessToken();
                    Log.i(TAG, temp.toString());

                    MyApiRetrofit myInfoService = ServiceInfoGenerator.retrieveInfoService(MyApiRetrofit.class, myAccessToken, "myusername");
                    Call<Authorize> call2 = myInfoService.retrieveMyInfo();
                    try 
                        Authorize user = call2.execute().body();
                     catch (IOException e) 
                        e.printStackTrace();
                    

                 else 
                    // error response, no access to resource?
                    Log.i(TAG, "error response");
                
            

            @Override
            public void onFailure(Call<Authorize> call, Throwable t) 
                // something went completely south (like no internet connection)
                Log.d(TAG, t.getMessage());
            
        );


        return null;
    



我正在遵循here 的指示。 我的改装版本是:

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'

最后的日志:

10-15 13:17:41.434 9968-9968 D/OkHttp: --> POST https://oauth.reddit.com/api/v1/me http/1.1
10-15 13:17:41.434 9968-9968 D/OkHttp: Content-Length: 0
10-15 13:17:41.434 9968-9968 D/OkHttp: Authorization: bearer tokenToken
10-15 13:17:41.434 9968-9968 D/OkHttp: User-Agent: MyRedditClient/0.1 by myusername
10-15 13:17:41.434 9968-9968 D/OkHttp: --> END POST (0-byte body)
10-15 13:17:41.988 9968-9968 D/OkHttp: <-- 404 Not Found https://oauth.reddit.com/api/v1/me (553ms)
10-15 13:17:41.988 9968-9968 D/OkHttp: Content-Type: application/json; charset=UTF-8
10-15 13:17:41.988 9968-9968 D/OkHttp: x-frame-options: SAMEORIGIN
10-15 13:17:41.988 9968-9968 D/OkHttp: x-content-type-options: nosniff
10-15 13:17:41.988 9968-9968 D/OkHttp: x-xss-protection: 1; mode=block
10-15 13:17:41.989 9968-9968 D/OkHttp: expires: -1
10-15 13:17:41.989 9968-9968 D/OkHttp: cache-control: private, s-maxage=0, max-age=0, must-revalidate, max-age=0, must-revalidate
10-15 13:17:41.990 9968-9968 D/OkHttp: x-ratelimit-remaining: 598.0
10-15 13:17:41.990 9968-9968 D/OkHttp: x-ratelimit-used: 2
10-15 13:17:41.990 9968-9968 D/OkHttp: x-ratelimit-reset: 136
10-15 13:17:41.990 9968-9968 D/OkHttp: set-cookie: loid=Fsx2GnGYmufCQZ6cfT; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: set-cookie: loidcreated=2016-10-15T10%3A17%3A44.173Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: x-ua-compatible: IE=edge
10-15 13:17:41.991 9968-9968 D/OkHttp: set-cookie: loid=Q52c9gouzuGGdg7UXW; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: set-cookie: loidcreated=2016-10-15T10%3A17%3A44.189Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Mon, 15-Oct-2018 10:17:44 GMT; secure
10-15 13:17:41.991 9968-9968 D/OkHttp: X-Moose: majestic
10-15 13:17:41.991 9968-9968 D/OkHttp: Content-Length: 38
10-15 13:17:41.992 9968-9968 D/OkHttp: Accept-Ranges: bytes
10-15 13:17:41.992 9968-9968 D/OkHttp: Date: Sat, 15 Oct 2016 10:17:44 GMT
10-15 13:17:41.992 9968-9968 D/OkHttp: Via: 1.1 varnish
10-15 13:17:41.992 9968-9968 D/OkHttp: Connection: keep-alive
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Served-By: cache-ams4426-AMS
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Cache: MISS
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Cache-Hits: 0
10-15 13:17:41.992 9968-9968 D/OkHttp: X-Timer: S1476526664.126987,VS0,VE109
10-15 13:17:41.993 9968-9968 D/OkHttp: Server: snooserv
10-15 13:17:42.002 9968-9968 D/OkHttp: "message": "Not Found", "error": 404
10-15 13:17:42.002 9968-9968 D/OkHttp: <-- END HTTP (38-byte body)

【问题讨论】:

【参考方案1】:

其中一个可能的原因可能是您的 BASE URL。

根据 Retrofit 2,base url 不能以 '/' 结尾。

请从基本 URL 中删除“/”并尝试一个。

在 Retrofit 1.9 中,它运行良好。

干杯!!!

【讨论】:

请使用库 compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' 分享您的请求日志 它会给请求和响应加上Header信息。要使用这个库调用 :: HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); // 设置你想要的日志级别 logging.setLevel(HttpLoggingInterceptor.Level.BODY); okHttpClientBuilder.interceptors().add(logging); 我已经编辑了我的帖子并添加了新的日志输出。 您的网址错误“https://oauth.reddit.com/api/v1/me”。它必须是 "https://www.reddit.com/api/v1/me" 。 ***注意在 https:// 之后添加空格。您需要删除它。 如果我将 url 更改为“reddit.com/api/v1/me”,我会收到“403 Forbidden”。【参考方案2】:

由于 Retrofit 2.0 如何使用 Http Resolve 来解析端点的 uri 方案,如果您将 baseurl 指定为 http://hello.com 并将端点 URL 指定为 /world/foo,它将中断。

您需要使用基本 URL http://hello.com/ 和端点 URL world/foo。

/ 有所作为。

如果对你有帮助,请通知我,否则我会给你另一个解决方案。 您的问题与我认为的这个问题相同:Link

你可以检查这个问题:Link

【讨论】:

感谢您的回答@jamil-hasnine-tamim,但我已经尝试过了! 不,它没有。现在我收到“错误 403,禁止访问”。 遇到了同样的问题,但在我这边,我切换帐户后它才开始工作。顺便说一句,当基本 URL 不是以 /.. 结尾时,Retrofit2 崩溃了,这很明显:) @milosmns 是的,你是对的 Retrofit2 由于/而崩溃【参考方案3】:

@POST("api/v1/me")

删除第一个字符 url 处的“/”,因为改造 2.0 需要 BASEURL 必须以“/”结尾。我在您的代码中找不到其他问题。如果有任何空值,您应该检查您的 Header 或检查 API 链接

【讨论】:

【参考方案4】:

您对端点 /api/v1/me 的 API 调用是 POST 方法

@POST("/api/v1/me")
Call<Authorize> retrieveMyInfo();

根据他们的documentation for enpoint /api/v1/me 你应该使用GET 请求。

@GET("/api/v1/me")
Call<Authorize> retrieveMyInfo();

我没有测试那个解决方案,但它似乎是 404 的原因,as in another post 它解决了这个问题(对于 python)。

【讨论】:

【参考方案5】:

我终于找到了我的解决方案!我用错误的 grant_type 拨打电话!我改变了它,现在它可以工作了!

【讨论】:

以上是关于Android Retrofit2 reddit 404 未找到的主要内容,如果未能解决你的问题,请参考以下文章

Retrofit2.0 android.os.NetworkOnMainThreadException解决方法

Android Studio - 使用 retrofit2 从 restdb 获取信息

Android Retrofit2中Part和PartMap的区别

Android 网络框架 Retrofit2.0介绍使用和封装

如何在Android上通过retrofit2调用带有Cognito Credentials的API网关?

Android 网络框架之Retrofit2使用详解及从源码中解析原理