在Android排球库中使用Cookie

Ras*_*tio 56 android android-volley

有人知道如何使用com.android.volley库将会话cookie附加到请求吗?当我登录网站时,它会给我一个会话cookie.浏览器会将该cookie发送回任何后续请求.排球似乎没有这样做,至少不是自动的.

谢谢.

Ada*_*dam 59

Volley本身并不实际发出HTTP请求,因此不直接管理Cookie.它改为使用HttpStack的实例来执行此操作.主要有两种实现方式:

  • HurlStack:在引擎盖下使用HttpUrlConnection
  • HttpClientStack:使用Apache HttpClient

Cookie管理是HttpStacks的责任.他们每个人处理不同的Cookie.

如果你需要支持<2.3,那么你应该使用HttpClientStack:

配置一个HttpClient实例,并将其传递给Volley,以便在引擎盖下使用:

// If you need to directly manipulate cookies later on, hold onto this client
// object as it gives you access to the Cookie Store
DefaultHttpClient httpclient = new DefaultHttpClient();

CookieStore cookieStore = new BasicCookieStore();
httpclient.setCookieStore( cookieStore );

HttpStack httpStack = new HttpClientStack( httpclient );
RequestQueue requestQueue = Volley.newRequestQueue( context, httpStack  );
Run Code Online (Sandbox Code Playgroud)

与此手动将cookie插入标头的优点是,您可以获得实际的cookie管理.商店中的Cookie将正确响应过期或更新它们的HTTP控件.

我更进了一步,将BasicCookieStore分类,这样我就可以自动将cookie保存到磁盘上.

然而!如果你没有需要支持旧版本的Android.只需使用此方法:

// CookieStore is just an interface, you can implement it and do things like
// save the cookies to disk or what ever.
CookieStore cookieStore = new MyCookieStore();
CookieManager manager = new CookieManager( cookieStore, CookiePolicy.ACCEPT_ALL );
CookieHandler.setDefault( manager  );

// Optionally, you can just use the default CookieManager
CookieManager manager = new CookieManager();
CookieHandler.setDefault( manager  );
Run Code Online (Sandbox Code Playgroud)

HttpURLConnection将隐式地查询CookieManager.HttpUrlConnection在实现和使用IMO方面也更高效,更清晰.

  • @Adam,谢谢,我也使用了默认的CookieManager,标题现在是正确的.但是当我重定向到另一个活动时,即使我在活动的创建时设置了cookiemanager,那些标题也不再是请求的一部分了,有没有办法让它在活动之间保持持久性? (2认同)

Ras*_*tio 40

vmirinov是对的!

以下是我解决问题的方法:

请求类:

public class StringRequest extends com.android.volley.toolbox.StringRequest {

    private final Map<String, String> _params;

    /**
     * @param method
     * @param url
     * @param params
     *            A {@link HashMap} to post with the request. Null is allowed
     *            and indicates no parameters will be posted along with request.
     * @param listener
     * @param errorListener
     */
    public StringRequest(int method, String url, Map<String, String> params, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, listener, errorListener);

        _params = params;
    }

    @Override
    protected Map<String, String> getParams() {
        return _params;
    }

    /* (non-Javadoc)
     * @see com.android.volley.toolbox.StringRequest#parseNetworkResponse(com.android.volley.NetworkResponse)
     */
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        // since we don't know which of the two underlying network vehicles
        // will Volley use, we have to handle and store session cookies manually
        MyApp.get().checkSessionCookie(response.headers);

        return super.parseNetworkResponse(response);
    }

    /* (non-Javadoc)
     * @see com.android.volley.Request#getHeaders()
     */
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = super.getHeaders();

        if (headers == null
                || headers.equals(Collections.emptyMap())) {
            headers = new HashMap<String, String>();
        }

        MyApp.get().addSessionCookie(headers);

        return headers;
    }
}
Run Code Online (Sandbox Code Playgroud)

和MyApp:

public class MyApp extends Application {
    private static final String SET_COOKIE_KEY = "Set-Cookie";
    private static final String COOKIE_KEY = "Cookie";
    private static final String SESSION_COOKIE = "sessionid";

    private static MyApp _instance;
  private RequestQueue _requestQueue;
  private SharedPreferences _preferences;

    public static MyApp get() {
        return _instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        _instance = this;
            _preferences = PreferenceManager.getDefaultSharedPreferences(this);
        _requestQueue = Volley.newRequestQueue(this);
    }

    public RequestQueue getRequestQueue() {
        return _requestQueue;
    }


    /**
     * Checks the response headers for session cookie and saves it
     * if it finds it.
     * @param headers Response Headers.
     */
    public final void checkSessionCookie(Map<String, String> headers) {
        if (headers.containsKey(SET_COOKIE_KEY)
                && headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
                String cookie = headers.get(SET_COOKIE_KEY);
                if (cookie.length() > 0) {
                    String[] splitCookie = cookie.split(";");
                    String[] splitSessionId = splitCookie[0].split("=");
                    cookie = splitSessionId[1];
                    Editor prefEditor = _preferences.edit();
                    prefEditor.putString(SESSION_COOKIE, cookie);
                    prefEditor.commit();
                }
            }
    }

    /**
     * Adds session cookie to headers if exists.
     * @param headers
     */
    public final void addSessionCookie(Map<String, String> headers) {
        String sessionId = _preferences.getString(SESSION_COOKIE, "");
        if (sessionId.length() > 0) {
            StringBuilder builder = new StringBuilder();
            builder.append(SESSION_COOKIE);
            builder.append("=");
            builder.append(sessionId);
            if (headers.containsKey(COOKIE_KEY)) {
                builder.append("; ");
                builder.append(headers.get(COOKIE_KEY));
            }
            headers.put(COOKIE_KEY, builder.toString());
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,标题可以像你拥有的那样返回"Set-Cookie",或者"set-cookie" - 在这种情况下,这个代码会破坏. (2认同)

Com*_*are 20

Volley的默认HTTP传输代码是HttpUrlConnection.如果我正确阅读文档,您需要选择自动会话cookie支持:

CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
Run Code Online (Sandbox Code Playgroud)

另请参见带有CookieManager的HttpURLConnection是否会自动处理会话cookie?

  • 默认的传输实现实际上取决于特定设备的android版本(`Gingerbread`及以上的`HttpUrlConnection`和以前版本的`HttpClient`)你不应该依赖它 (7认同)
  • 如果我使用凌空,在哪里添加此代码! (5认同)
  • 目前,Gingerbread下面的Android用户比例为2.2%.我个人并不关心他们.所以我同意CommonsWare并在HurlStack构造函数中添加了`CookieHandler.setDefault(new CookieManager(null,CookiePolicy.ACCEPT_ALL));`.效果很好. (4认同)

Adn*_*afa 14

伙计们onCreate用你的方法来试试这个AppController.java

  CookieHandler.setDefault(new CookieManager());
Run Code Online (Sandbox Code Playgroud)

希望它能节省开发人员的时间.我在调试和搜索适当的解决方案时浪费了四个小时.


Luk*_*kas 10

如果有多个"Set-Cookie"标头,则@Rastio解决方案不起作用.我包装了默认的CookieManager cookie存储库,在添加cookie之前,我使用Gson将其保存在SharedPreferences中以序列化cookie.

这是cookie存储包装器的一个示例:

import android.content.Context;
import android.net.Uri;
import android.util.Log;

import com.google.gson.Gson;

import java.net.CookieManager;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.util.List;

/**
 * Class that implements CookieStore interface. This class saves to SharedPreferences the session
 * cookie.
 *
 * Created by lukas.
 */
public class PersistentCookieStore implements CookieStore {

    private CookieStore mStore;
    private Context mContext;
    private Gson mGson;

    public PersistentCookieStore(Context context) {
        // prevent context leaking by getting the application context
        mContext = context.getApplicationContext();
        mGson = new Gson();

        // get the default in memory store and if there is a cookie stored in shared preferences,
        // we added it to the cookie store
        mStore = new CookieManager().getCookieStore();
        String jsonSessionCookie = Prefs.getJsonSessionCookie(mContext);
        if (!jsonSessionCookie.equals(Prefs.DEFAULT_STRING)) {
            HttpCookie cookie = mGson.fromJson(jsonSessionCookie, HttpCookie.class);
            mStore.add(URI.create(cookie.getDomain()), cookie);
        }
    }

    @Override
    public void add(URI uri, HttpCookie cookie) {
        if (cookie.getName().equals("sessionid")) {
            // if the cookie that the cookie store attempt to add is a session cookie,
            // we remove the older cookie and save the new one in shared preferences
            remove(URI.create(cookie.getDomain()), cookie);
            Prefs.saveJsonSessionCookie(mContext, mGson.toJson(cookie));
        }

        mStore.add(URI.create(cookie.getDomain()), cookie);
    }

    @Override
    public List<HttpCookie> get(URI uri) {
        return mStore.get(uri);
    }

    @Override
    public List<HttpCookie> getCookies() {
        return mStore.getCookies();
    }

    @Override
    public List<URI> getURIs() {
        return mStore.getURIs();
    }

    @Override
    public boolean remove(URI uri, HttpCookie cookie) {
        return mStore.remove(uri, cookie);
    }

    @Override
    public boolean removeAll() {
        return mStore.removeAll();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,使用刚刚在CookieManager中设置的cookie存储,就是这样!

CookieManager cookieManager = new CookieManager(new PersistentCookieStore(mContext),
    CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
Run Code Online (Sandbox Code Playgroud)


And*_*n K 5

我知道帖子有点旧,但是我们经历了最近这个问题,我们需要在服务器之间共享一个已登录用户的会话,并且服务器端解决方案开始要求客户端通过cookie提供一个值.我们发现的一个解决方案是向RequestQueue对象添加一个参数,getRequestQueue在实例化RequestQueue下面的链接上找到的方法之前,方法中的代码片段,并解决问题,不确定如何,但它开始工作.

访问http://woxiangbo.iteye.com/blog/1769122

public class App extends Application {

    public static final String TAG = App.class.getSimpleName();

    private static App         mInstance;

    public static synchronized App getInstance() {
        return App.mInstance;
    }

    private RequestQueue mRequestQueue;

    public <T> void addToRequestQueue( final Request<T> req ) {
        req.setTag( App.TAG );
        this.getRequestQueue().add( req );
    }

    public <T> void addToRequestQueue( final Request<T> req, final String tag ) {
        req.setTag( TextUtils.isEmpty( tag ) ? App.TAG : tag );
        this.getRequestQueue().add( req );
    }

    public void cancelPendingRequests( final Object tag ) {
        if ( this.mRequestQueue != null ) {
            this.mRequestQueue.cancelAll( tag );
        }
    }

    public RequestQueue getRequestQueue() {

        if ( this.mRequestQueue == null ) {


            DefaultHttpClient mDefaultHttpClient = new DefaultHttpClient();

            final ClientConnectionManager mClientConnectionManager = mDefaultHttpClient.getConnectionManager();
            final HttpParams mHttpParams = mDefaultHttpClient.getParams();
            final ThreadSafeClientConnManager mThreadSafeClientConnManager = new ThreadSafeClientConnManager( mHttpParams, mClientConnectionManager.getSchemeRegistry() );

            mDefaultHttpClient = new DefaultHttpClient( mThreadSafeClientConnManager, mHttpParams );

            final HttpStack httpStack = new HttpClientStack( mDefaultHttpClient );

            this.mRequestQueue = Volley.newRequestQueue( this.getApplicationContext(), httpStack );
        }

        return this.mRequestQueue;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        App.mInstance = this;
    }
}
Run Code Online (Sandbox Code Playgroud)

//设置标记值

ObjectRequest.setHeader( "Cookie", "JSESSIONID=" + tokenValueHere );
Run Code Online (Sandbox Code Playgroud)