HttpClient 4.0.x Tips

HttpClient 4的变化确实有些大,没有系统的教程,每次碰上问题只能逐一解决~

原文转自:http://www.cnblogs.com/mmjx/archive/2011/12/06/2278150.html


最近用HttpClient做一个工具做代理访问服务器的WebService,由于服务器是采用NTLM验证的,再加上网上的很多资料大多是关于HttpClient 3的,折磨了好久才搞定。这里记录一下,供以后参考使用。

 

关于文中内容,我不按照手册上的写法,而是整理成小Tips,希望看起来简单轻松一点。

 

1, HttpClient 4.x 库可以自己处理Cookie

这一点误导了我很久,HttpClient 4.x提供了CookieStore来帮助程序员管理本地Cookie,并且在Http请求的过程中,如果服务器的返回中带有Set-Cookie这样的字段,当前HttpClient的CookieStore中就会增加一条新的Cookie。

(注意:误导来了)很多网上的资料认为即便当前的HttpClient的CookieStore中有服务器返回的Cookie,HttpClient在下次请求的时候也不会主动加上,需要用户自己手动添加,添加的方法有两种,一种是直接SetHeader,一种是设置CookieStore,比如:

if (!httpclient.getCookieStore().getCookies().isEmpty()) {
                Cookie getCookie = httpclient.getCookieStore().getCookies().get(0);
                BasicCookieStore cookieStore =newBasicCookieStore(); 
                cookieStore.addCookie(getCookie);
                httpclient.setCookieStore(cookieStore);
}


但事实是:

HttpClient是否在下次请求中携带从服务器端请求来的Cookie,完全是由设置决定的。

httpclient.getParams.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BEST_MATCH)

如果设置为Cookie策略为BEST_MATCH的话,HttpClient会在请求中携带由服务器返回的Cookie。如果按照上面的写法,手动添加了CookieStore,那么就会在下次请求中夹带着两个Cookie,Cookie和Cookie2。

 

2,NTLM如何使用HttpClient模拟

NTLM分为很多很多版本,HttpClient 3.x是支持NTLMv1,而因为legal的原因,HttpClient 4.0.x不再支持,转而使用jcifs库来支持NTLM,但是估计还是只支持v1,而没有继续扩展支持更高级的验证身份。

如何使用NTLM验证呢?首先NTLM过程至少要3次请求才能完成一个资源的请求,我们不需要手动模拟这三个请求,只需要使用NTLM的功能就可以了。

配置如下:

httpclient = new DefaultHttpClient();       
httpclient.getAuthSchemes().register("ntlm",newNTLMSchemeFactory());
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY,
        newNTCredentials(asi.getUser(), asi.getPass(), asi.SERVER_NAME, asi.getDomain()));
List<String> authpref =newArrayList<String>();
authpref.add(AuthPolicy.NTLM); 
httpclient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF, authpref);

其中的NTLMSchemeFactory实现如下:

package ntml;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeFactory;
import org.apache.http.impl.auth.NTLMScheme;
import org.apache.http.params.HttpParams;
public class NTLMSchemeFactory implementsAuthSchemeFactory {
    publicAuthScheme newInstance(finalHttpParams params) {
        returnnewNTLMScheme(newJCIFSEngine());
    }
}
package ntml;
import jcifs.ntlmssp.NtlmFlags;
import jcifs.ntlmssp.Type1Message; 
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message; 
import jcifs.util.Base64;
import org.apache.http.impl.auth.NTLMEngine;   
import org.apache.http.impl.auth.NTLMEngineException;
import java.io.IOException;
public final class JCIFSEngineimplementsNTLMEngine {
    privatestaticfinal int TYPE_1_FLAGS =
            NtlmFlags.NTLMSSP_NEGOTIATE_56 |   
            NtlmFlags.NTLMSSP_NEGOTIATE_128 |  
            NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 |
            NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
 
            NtlmFlags.NTLMSSP_REQUEST_TARGET;
     
    publicString generateType1Msg(finalString domain,finalString workstation)  
            throwsNTLMEngineException {   
        finalType1Message type1Message =newType1Message(TYPE_1_FLAGS, domain, workstation);
        returnBase64.encode(type1Message.toByteArray());
    }  
    publicString generateType3Msg(finalString username,finalString password,   
            finalString domain,finalString workstation,finalString challenge) 
            throwsNTLMEngineException {
        Type2Message type2Message; 
        try{  
            type2Message =newType2Message(Base64.decode(challenge)); 
        }catch(finalIOException exception) {
            thrownewNTLMEngineException("Invalid NTLM type 2 message", exception);
        }
        finalinttype2Flags = type2Message.getFlags();
        finalinttype3Flags = type2Flags  
                & (0xffffffff^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        finalType3Message type3Message =newType3Message(type2Message, password, domain,
                username, workstation, type3Flags);
        returnBase64.encode(type3Message.toByteArray());  
    }
}


  

3, NTLM中的Cookie问题

由于NTLM的几个过程中,我们无法插一脚,所以实际的NTLM认证过程中,对于哪些服务器产生产生Cookie,并要求客户端携Cookie请求以让服务器绑定Session的情况,如果不利用tips 1里面的自动携带Cookie,可能就不能做什么了。这也是前一段时间卡住最主要的内容。

 

4,下一阶段准备尝试使用HttpClient编写一个库来爬Baidu或者douban的音乐...已经有Python的了,哈哈。。。

你可能感兴趣的:(HttpClient 4.0.x Tips)