多线程的CookieManager [英] CookieManager for multiple threads

查看:219
本文介绍了多线程的CookieManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



但是每个连接似乎都会覆盖对方的cookies,导致连接使用错误的cookie。



在线程类的构造函数中:

  manager = new CookieManager 
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);

以任何方式管理每个主题或每个课程的Cookie?



新的失败的尝试:



现在每个线程都使用它自己的索引,但他们似乎仍然以cookie的方式覆盖。任何想法?

  public class threadedCookieStore implements CookieStore,Runnable {
CookieStore [] store = new CookieStore [1000]
int index;

public threadedCookieStore(int new_index){
index = new_index;
//获取内存cookie存储中的默认值
store [index] = new CookieManager()。getCookieStore();


// todo:从持久性存储器中读取cookie
//并添加它们store

//添加一个关闭挂钩以写出in memory cookies
Runtime.getRuntime()。addShutdownHook(new Thread(this));
}

public void run(){
// todo:将cookie存储到永久存储器
}

public void add (URI uri,HttpCookie cookie){
store [index] .add(uri,cookie);
}

public List< HttpCookie> get(URI uri){
return store [index] .get(uri);
}

public List< HttpCookie> getCookies(){
return store [index] .getCookies();
}

public List< URI> getURIs(){
return store [index] .getURIs();
}

public boolean remove(URI uri,HttpCookie cookie){
return store [index] .remove(uri,cookie);
}

public boolean removeAll(){
return store [index] .removeAll();
}
}

在类中:

  threadedCookieStore cookiestore = new threadedCookieStore(index); 

manager = new CookieManager(cookiestore,CookiePolicy.ACCEPT_ALL);
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);


解决方案

感谢大家。



我upvote所有的答案,但没有一个完整的解决方案。



由于google'ing这个问题导致这个页面,发布完整的解决方案并接受我自己的回答:



HowTo:



1扩展 CookieHandler 到 SessionCookieManager



这是基于如何使用HttpURLConnection和CookieManager中的每个连接使用不同的Cookie ,nivs正确地描述它,不提供一个完整的解决方案。所以大多数/所有的功劳都归他,我只是做完整的HowTo。 SessionCookieManager基于 Java 的源代码 http://docs.oracle.com/javase/7/docs/api/java/net/CookieManager.html

  import java.io.IOException; 
import java.net.CookieHandler;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

public class SessionCookieManager extends CookieHandler
{
private CookiePolicy policyCallback;


public SessionCookieManager(){
this(null,null);
}

private final static SessionCookieManager ms_instance = new SessionCookieManager();

public static SessionCookieManager getInstance()
{
return ms_instance;
}

private final static ThreadLocal< CookieStore> ms_cookieJars = new ThreadLocal< CookieStore>(){
@Override
protected synchronized CookieStore initialValue(){return new InMemoryCookieStore(); }
};

public void clear()
{
getCookieStore()。removeAll();
}
public SessionCookieManager(CookieStore store,
CookiePolicy cookiePolicy)
{
//如果没有指定就使用默认cookie策略
policyCallback =(cookiePolicy = = null)? CookiePolicy.ACCEPT_ALL //注意,我将其更改为ACCEPT_ALL
:cookiePolicy;

//如果未指定要使用的CookieStore,请使用默认值

}
public void setCookiePolicy(CookiePolicy cookiePolicy){
if(cookiePolicy!= null)policyCallback = cookiePolicy;
}

public CookieStore getCookieStore(){
return ms_cookieJars.get();
}

public Map< String,List< String>>
get(URI uri,Map< String,List< String>> requestHeaders)
throws IOException
{
//前提条件检查
if(uri = = null || requestHeaders == null){
throw new IllegalArgumentException(Argument is null);
}

映射< String,List< String>> cookieMap =
new java.util.HashMap< String,List< String>>();
//如果没有默认值CookieStore,我们没有办法获取任何cookie
if(getCookieStore()== null)
return Collections.unmodifiableMap(cookieMap);

List< HttpCookie> cookies = new java.util.ArrayList< HttpCookie>();
for(HttpCookie cookie:getCookieStore()。get(uri)){
//应用路径匹配规则(RFC 2965 sec。3.3.4)
if(pathMatches(uri.getPath (),cookie.getPath())){
cookie.add(cookie);
}
}

//应用排序规则(RFC 2965 sec。3.3.4)
List< String> cookieHeader = sortByPath(cookies);

cookieMap.put(Cookie,cookieHeader);
return Collections.unmodifiableMap(cookieMap);
}


public void
put(URI uri,Map< String,List< String>> responseHeaders)
throws IOException
{
// pre-condition check
if(uri == null || responseHeaders == null){
throw new IllegalArgumentException(Argument is null);
}


//如果没有默认CookieStore,不需要记住任何cookie
if(getCookieStore()== null)
return;

for(String headerKey:responseHeaders.keySet()){
// RFC 2965 3.2.2,密钥必须是'Set-Cookie2'
//我们也接受' Set-Cookie'这里为向后兼容
if(headerKey == null
||!(headerKey.equalsIgnoreCase(Set-Cookie2)
|| headerKey.equalsIgnoreCase )


{
continue;
}

for(String headerValue:responseHeaders.get(headerKey)){
try {
List< HttpCookie> cookies = HttpCookie.parse(headerValue);
for(HttpCookie cookie:cookies){
if(shouldAcceptInternal(uri,cookie)){
getCookieStore()。add(uri,cookie);
}
}
} catch(IllegalArgumentException e){
//无效的set-cookie头字符串
// no-op
}
}
}
}


/ * ----------------私人操作-------- * /

//确定是否接受此cookie
private boolean shouldAcceptInternal(URI uri,HttpCookie cookie){
try {
return policyCallback.shouldAccept(uri,cookie);
} catch(Exception ignored){//预防恶意回调
return false;
}
}


/ *
*路径匹配算法,由RFC 2965定义
* /
private boolean pathMatches(String path,String pathToMatchWith){
if(path == pathToMatchWith)
return true;
if(path == null || pathToMatchWith == null)
return false;
if(path.startsWith(pathToMatchWith))
return true;

return false;
}


/ *
*根据路径排序Cookie:具有更多特定路径属性的cookie。定义在RFC 2965 sec。 3.3.4
* /
private List< String> sortByPath(List< HttpCookie> cookies){
Collections.sort(cookie,new CookiePathComparator());

List< String> cookieHeader = new java.util.ArrayList< String>();
for(HttpCookie cookie:cookies){
// Netscape cookie规范和RFC 2965有不同的Cookie格式
// header; RFC 2965需要前导$ Version =1字符串,而Netscape
//不需要。
//这里的解决方法是提前添加$ Version =1字符串
if(cookies.indexOf(cookie)== 0&& cookie.getVersion()> 0) {
cookieHeader.add($ Version = \1\);
}

cookieHeader.add(cookie.toString());
}
return cookieHeader;
}


静态类CookiePathComparator实现Comparator< HttpCookie> {
public int compare(HttpCookie c1,HttpCookie c2){
if(c1 == c2)return 0;
if(c1 == null)return -1;
if(c2 == null)return 1;

//路径规则仅适用于同名的cookie
if(!c1.getName()。equals(c2.getName()))return 0;

//具有更多特定路径属性的那些路径属性先于那些具有较少特定路径的路径属性
if(c1.getPath()。startsWith(c2.getPath()))
return -1;
else if(c2.getPath()。startsWith(c1.getPath()))
return 1;
else
return 0;
}
}
}

请注意,在我的情况下将 CookiePolicy 的默认值更改为 ACCEPT_ALL



2在全局范围内,在运行任何线程之前,请调用:



  CookieHandler.setDefault(SessionCookieManager.getInstance 



3当你的线程完成后,调用它:



  SessionCookieManager.getInstance()。clear(); 

:不是我的想法,只是把它放在一起。所有信用分配到 Java http://stackoverflow.com/users/1442259 / nivs


I am trying to make multiple connections via threads.

But every connection seems to override the other's cookies, resulting in the connections using the wrong cookies.

inside the threaded class's constructor:

    manager = new CookieManager();
    manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
    CookieHandler.setDefault(manager);

Any way to manage the cookies per thread or per class?

New failed try:

Now every thread is using it's own index, yet they still seem to override each other cookie-wise. Any ideas?

public class threadedCookieStore implements CookieStore, Runnable {
    CookieStore[] store = new CookieStore[1000];
    int index;

    public threadedCookieStore(int new_index) {
        index = new_index;
        // get the default in memory cookie store
        store[index] = new CookieManager().getCookieStore();


        // todo: read in cookies from persistant storage
        // and add them store

        // add a shutdown hook to write out the in memory cookies
        Runtime.getRuntime().addShutdownHook(new Thread(this)); 
    }

    public void run() {
        // todo: write cookies in store to persistent storage
    }

    public void add(URI uri, HttpCookie cookie) {
        store[index].add(uri, cookie);
    }

    public List<HttpCookie> get(URI uri) {
        return store[index].get(uri);
    }

    public List<HttpCookie> getCookies() {
        return store[index].getCookies();
    }

    public List<URI> getURIs() {
        return store[index].getURIs();
    }

    public boolean remove(URI uri, HttpCookie cookie) {
        return store[index].remove(uri, cookie);
    }

     public boolean removeAll()  {
         return store[index].removeAll();
    }
}

Within the class:

threadedCookieStore cookiestore = new threadedCookieStore(index);

manager = new CookieManager(cookiestore,CookiePolicy.ACCEPT_ALL);
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);

解决方案

Thanks everyone.

I upvoted all the answers, yet none had a complete solution.

Since google'ing this problem leads to this page here, I'll post the complete solution and accept my own answer:

HowTo:

1 Extend CookieHandler to SessionCookieManager

this is based on How to use different cookies for each connection using HttpURLConnection and the CookieManager in Java , nivs describes it correctly, doesn't provide a full solution tho. So most/all credit goes to him, I'm just making the complete HowTo. The SessionCookieManager is based on Java 's source code http://docs.oracle.com/javase/7/docs/api/java/net/CookieManager.html

import java.io.IOException;
import java.net.CookieHandler;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

public class SessionCookieManager extends CookieHandler
{
    private CookiePolicy policyCallback;


    public SessionCookieManager() {
        this(null, null);
    }

    private final static SessionCookieManager ms_instance = new SessionCookieManager();

    public static SessionCookieManager getInstance()
    {
        return ms_instance;
    }

    private final static ThreadLocal<CookieStore> ms_cookieJars = new ThreadLocal<CookieStore>() {
        @Override
        protected synchronized CookieStore initialValue() { return new InMemoryCookieStore(); }
    };

    public void clear()
    {
        getCookieStore().removeAll();
    }
    public SessionCookieManager(CookieStore store,
                         CookiePolicy cookiePolicy)
    {
        // use default cookie policy if not specify one
        policyCallback = (cookiePolicy == null) ? CookiePolicy.ACCEPT_ALL //note that I changed it to ACCEPT_ALL
                                                : cookiePolicy;

        // if not specify CookieStore to use, use default one

    }
    public void setCookiePolicy(CookiePolicy cookiePolicy) {
        if (cookiePolicy != null) policyCallback = cookiePolicy;
    }

    public CookieStore getCookieStore() {
        return ms_cookieJars.get();
    }

    public Map<String, List<String>>
        get(URI uri, Map<String, List<String>> requestHeaders)
        throws IOException
    {
        // pre-condition check
        if (uri == null || requestHeaders == null) {
            throw new IllegalArgumentException("Argument is null");
        }

        Map<String, List<String>> cookieMap =
                        new java.util.HashMap<String, List<String>>();
        // if there's no default CookieStore, no way for us to get any cookie
        if (getCookieStore() == null)
            return Collections.unmodifiableMap(cookieMap);

        List<HttpCookie> cookies = new java.util.ArrayList<HttpCookie>();
        for (HttpCookie cookie : getCookieStore().get(uri)) {
            // apply path-matches rule (RFC 2965 sec. 3.3.4)
            if (pathMatches(uri.getPath(), cookie.getPath())) {
                cookies.add(cookie);
            }
        }

        // apply sort rule (RFC 2965 sec. 3.3.4)
        List<String> cookieHeader = sortByPath(cookies);

        cookieMap.put("Cookie", cookieHeader);
        return Collections.unmodifiableMap(cookieMap);
    }


    public void
        put(URI uri, Map<String, List<String>> responseHeaders)
        throws IOException
    {
        // pre-condition check
        if (uri == null || responseHeaders == null) {
            throw new IllegalArgumentException("Argument is null");
        }


        // if there's no default CookieStore, no need to remember any cookie
        if (getCookieStore() == null)
            return;

        for (String headerKey : responseHeaders.keySet()) {
            // RFC 2965 3.2.2, key must be 'Set-Cookie2'
            // we also accept 'Set-Cookie' here for backward compatibility
            if (headerKey == null
                || !(headerKey.equalsIgnoreCase("Set-Cookie2")
                     || headerKey.equalsIgnoreCase("Set-Cookie")
                    )
                )
            {
                continue;
            }

            for (String headerValue : responseHeaders.get(headerKey)) {
                try {
                    List<HttpCookie> cookies = HttpCookie.parse(headerValue);
                    for (HttpCookie cookie : cookies) {
                        if (shouldAcceptInternal(uri, cookie)) {
                            getCookieStore().add(uri, cookie);
                        }
                    }
                } catch (IllegalArgumentException e) {
                    // invalid set-cookie header string
                    // no-op
                }
            }
        }
    }


    /* ---------------- Private operations -------------- */

    // to determine whether or not accept this cookie
    private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) {
        try {
            return policyCallback.shouldAccept(uri, cookie);
        } catch (Exception ignored) { // pretect against malicious callback
            return false;
        }
    }


    /*
     * path-matches algorithm, as defined by RFC 2965
     */
    private boolean pathMatches(String path, String pathToMatchWith) {
        if (path == pathToMatchWith)
            return true;
        if (path == null || pathToMatchWith == null)
            return false;
        if (path.startsWith(pathToMatchWith))
            return true;

        return false;
    }


    /*
     * sort cookies with respect to their path: those with more specific Path attributes
     * precede those with less specific, as defined in RFC 2965 sec. 3.3.4
     */
    private List<String> sortByPath(List<HttpCookie> cookies) {
        Collections.sort(cookies, new CookiePathComparator());

        List<String> cookieHeader = new java.util.ArrayList<String>();
        for (HttpCookie cookie : cookies) {
            // Netscape cookie spec and RFC 2965 have different format of Cookie
            // header; RFC 2965 requires a leading $Version="1" string while Netscape
            // does not.
            // The workaround here is to add a $Version="1" string in advance
            if (cookies.indexOf(cookie) == 0 && cookie.getVersion() > 0) {
                cookieHeader.add("$Version=\"1\"");
            }

            cookieHeader.add(cookie.toString());
        }
        return cookieHeader;
    }


    static class CookiePathComparator implements Comparator<HttpCookie> {
        public int compare(HttpCookie c1, HttpCookie c2) {
            if (c1 == c2) return 0;
            if (c1 == null) return -1;
            if (c2 == null) return 1;

            // path rule only applies to the cookies with same name
            if (!c1.getName().equals(c2.getName())) return 0;

            // those with more specific Path attributes precede those with less specific
            if (c1.getPath().startsWith(c2.getPath()))
                return -1;
            else if (c2.getPath().startsWith(c1.getPath()))
                return 1;
            else
                return 0;
        }
    }
}

Note that in my case I changed the default value of CookiePolicy to ACCEPT_ALL

2 In global scope, before running any threads, call:

CookieHandler.setDefault(SessionCookieManager.getInstance());

3 When your thread is finished, call inside of it:

SessionCookieManager.getInstance().clear();

again: not my idea, just putting it together. All credit goes to Java and http://stackoverflow.com/users/1442259/nivs

这篇关于多线程的CookieManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆