You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit请求登录遇HTTP 401未授权错误排查求助

Retrofit调用Spring登录接口返回HTTP 401 Unauthorized并触发空指针异常

问题概述

  • Postman发送POST请求(Body为JSON格式用户名密码)可正常登录本地Spring Web服务器
  • Android环境使用Retrofit复刻相同请求时,返回HTTP 401 Unauthorized错误,且response.body()为null,触发空指针异常
  • 已尝试修改接口端点、BaseURL、GsonBuilder配置,问题未解决

核心排查方向

1. 请求头差异

Postman会自动添加部分默认请求头(如Content-Type: application/json),Retrofit若未明确设置,可能导致Spring端无法正确解析请求体。

2. JSON序列化/反序列化不匹配

Android实体类的字段名、类型与Spring接口接收的参数不匹配,比如大小写不一致、缺少@SerializedName映射,导致请求体解析失败,触发认证失败。

3. 本地服务器访问地址错误

Android模拟器访问本地PC服务器时,不能直接用localhost,需替换为10.0.2.2;真机需使用电脑的局域网IP地址,否则无法连接服务器。

4. Spring端CSRF校验拦截

若Spring开启了CSRF保护,Postman会自动处理Cookie中的CSRF token,但Retrofit默认不会携带,导致请求被拦截返回401。

5. 空指针未做防护

未先判断请求是否成功、response.body()是否为null就直接操作,触发空指针异常。

解决方案

1. 确保请求头正确设置

通过OkHttpClient拦截器全局添加Content-Type,或在接口方法上用@Headers注解指定:

// 全局拦截器方式
OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(chain -> {
            Request request = chain.request().newBuilder()
                    .header("Content-Type", "application/json")
                    .build();
            return chain.proceed(request);
        })
        .build();

// 接口方法注解方式
@POST("login")
@Headers("Content-Type: application/json")
Call<LoginResponse> login(@Body LoginRequest loginRequest);

2. 统一JSON字段映射

确保Android实体类与Spring接收参数完全匹配,字段名不一致时用@SerializedName指定:

public class LoginRequest {
    @SerializedName("username") // 与Spring接口参数名一致
    private String userName;
    @SerializedName("password")
    private String passWord;

    // getter、setter
}

3. 修正本地服务器地址

  • 模拟器:将BaseURL改为http://10.0.2.2:端口号/
  • 真机:将BaseURL改为http://电脑局域网IP:端口号/(如http://192.168.1.100:8080/)

4. 处理CSRF校验

若Spring开启CSRF,需先获取CSRF token并加入请求头:

  1. 先发送GET请求获取Cookie中的XSRF-TOKEN
  2. 在登录请求中添加X-XSRF-TOKEN头,值为获取到的token
  3. 确保OkHttpClient启用Cookie持久化:
CookieJar cookieJar = new CookieJar() {
    private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

    @Override
    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
        cookieStore.put(url.host(), cookies);
    }

    @Override
    public List<Cookie> loadForRequest(HttpUrl url) {
        List<Cookie> cookies = cookieStore.get(url.host());
        return cookies != null ? cookies : new ArrayList<>();
    }
};

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .cookieJar(cookieJar)
        .addInterceptor(chain -> {
            Request request = chain.request();
            String xsrfToken = null;
            List<Cookie> cookies = cookieJar.loadForRequest(request.url());
            for (Cookie cookie : cookies) {
                if ("XSRF-TOKEN".equals(cookie.name())) {
                    xsrfToken = cookie.value();
                    break;
                }
            }
            if (xsrfToken != null) {
                request = request.newBuilder()
                        .header("X-XSRF-TOKEN", xsrfToken)
                        .build();
            }
            return chain.proceed(request);
        })
        .build();

5. 空指针防护

处理响应时先判断请求是否成功,再检查response.body()是否为null:

call.enqueue(new Callback<LoginResponse>() {
    @Override
    public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
        if (response.isSuccessful()) {
            LoginResponse body = response.body();
            if (body != null) {
                // 处理登录成功逻辑
            } else {
                Log.e("Login", "响应体为空");
            }
        } else {
            // 打印错误响应内容,排查401原因
            try {
                String errorBody = response.errorBody().string();
                Log.e("LoginError", "错误码:" + response.code() + ",错误信息:" + errorBody);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onFailure(Call<LoginResponse> call, Throwable t) {
        Log.e("LoginFailure", t.getMessage());
    }
});

内容的提问来源于stack exchange,提问作者Wabi-Sabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 07:31:06