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

Android中Volley获取Django登录Cookie并设置到后续请求的实现

解决Android Volley获取Django登录Cookie并在后续请求携带的问题

核心思路

Django登录成功后会在响应头的Set-Cookie字段返回csrftoken和sessionid,我们需要从响应头提取这两个值并持久化保存,后续请求时在请求头中携带Cookie字段(包含这两个值)以及X-CSRFToken字段(对应csrftoken值)。

完整代码实现

1. 自定义JsonObjectRequest获取响应头

先定义一个能监听响应头的自定义请求类,方便获取Set-Cookie:

import com.android.volley.NetworkResponse;
import com.android.volley.Response;
import com.android.volley.toolbox.JsonObjectRequest;
import org.json.JSONObject;
import java.util.Map;

public class CustomJsonObjectRequest extends JsonObjectRequest {
    private OnHeadersReceivedListener headersListener;

    public interface OnHeadersReceivedListener {
        void onHeadersReceived(Map<String, String> headers);
    }

    public CustomJsonObjectRequest(int method, String url, JSONObject jsonRequest,
                                   Response.Listener<JSONObject> listener, Response.ErrorListener errorListener,
                                   OnHeadersReceivedListener headersListener) {
        super(method, url, jsonRequest, listener, errorListener);
        this.headersListener = headersListener;
    }

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        // 触发响应头监听
        if (headersListener != null) {
            headersListener.onHeadersReceived(response.headers);
        }
        return super.parseNetworkResponse(response);
    }
}

2. 修改登录方法,提取并保存Cookie

在你的Activity中初始化SharedPreferences存储Cookie,然后修改test()方法:

import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.Volley;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;

public class LoginActivity extends AppCompatActivity {
    private SharedPreferences sharedPref;
    private SharedPreferences.Editor editor;
    private String UEmail; // 需提前赋值用户邮箱
    private String UPassword; // 需提前赋值用户密码

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        
        // 初始化SharedPreferences用于保存Cookie
        sharedPref = getSharedPreferences("AppCookiePrefs", MODE_PRIVATE);
        editor = sharedPref.edit();
    }

    private void test() {
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        String url_ = "https://xxxx.com/api/BF";
        Map<String, String> params = new HashMap<>();
        params.put("Email", UEmail);
        params.put("Password", UPassword);
        JSONObject JOParams = new JSONObject(params);

        CustomJsonObjectRequest JORequest = new CustomJsonObjectRequest(
                Request.Method.POST, url_, JOParams,
                response -> {
                    try {
                        String status_ = response.getString("Status");
                        if (status_.equals("OK_")) {
                            Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();
                        }
                    } catch (Exception e) {
                        Toast.makeText(this, "数据解析错误", Toast.LENGTH_SHORT).show();
                    }
                },
                error -> Toast.makeText(this, "连接失败", Toast.LENGTH_LONG).show(),
                headers -> {
                    // 从响应头获取Set-Cookie
                    String setCookie = headers.get("Set-Cookie");
                    if (setCookie != null) {
                        // 解析csrftoken和sessionid
                        String csrfToken = extractCookieValue(setCookie, "csrftoken");
                        String sessionId = extractCookieValue(setCookie, "sessionid");
                        
                        // 保存到SharedPreferences
                        if (csrfToken != null) {
                            editor.putString("csrftoken", csrfToken);
                        }
                        if (sessionId != null) {
                            editor.putString("sessionid", sessionId);
                        }
                        editor.apply();
                    }
                });

        requestQueue.add(JORequest);
    }

    // 从Set-Cookie字符串中提取指定Cookie的值
    private String extractCookieValue(String setCookie, String cookieName) {
        String[] cookies = setCookie.split(";");
        for (String cookie : cookies) {
            cookie = cookie.trim();
            if (cookie.startsWith(cookieName + "=")) {
                return cookie.substring(cookieName.length() + 1);
            }
        }
        return null;
    }
}

3. 后续请求携带Cookie和CSRF Token

发起后续请求时,从SharedPreferences取出保存的值,添加到请求头:

private void sendSubsequentRequest() {
    RequestQueue requestQueue = Volley.newRequestQueue(this);
    String url = "https://xxxx.com/api/your-subsequent-api";
    
    // 从SharedPreferences获取保存的Cookie值
    String csrfToken = sharedPref.getString("csrftoken", "");
    String sessionId = sharedPref.getString("sessionid", "");

    JsonObjectRequest request = new JsonObjectRequest(
            Request.Method.GET, url, null,
            response -> {
                // 处理后续请求响应逻辑
            },
            error -> {
                // 处理请求错误逻辑
            }) {
        @Override
        public Map<String, String> getHeaders() {
            Map<String, String> headers = new HashMap<>();
            // 添加Cookie头
            if (!csrfToken.isEmpty() && !sessionId.isEmpty()) {
                headers.put("Cookie", "csrftoken=" + csrfToken + "; sessionid=" + sessionId);
            }
            // 添加X-CSRFToken头(Django的POST/PUT/DELETE请求必须携带)
            if (!csrfToken.isEmpty()) {
                headers.put("X-CSRFToken", csrfToken);
            }
            return headers;
        }
    };

    requestQueue.add(request);
}

注意事项

  • 若为跨域场景,需确保Django后端配置CSRF_TRUSTED_ORIGINS包含你的应用域名/IP
  • HTTPS请求下Cookie的Secure属性会生效,需保证请求协议一致
  • Cookie的HttpOnly属性不影响Volley从响应头读取值,无需额外处理

内容的提问来源于stack exchange,提问作者rahim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:07:20