|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
当然你可以把你最基本的功能放出来的时候就放出来,比如放到论坛上,让大家都参与,client|cookie|cookies|多线程
― 作者 sunggsun @ 20:26
8、Cookies
HttpClient能主动办理cookie,包含答应办事器设置cookie并在需求的时分主动将cookie前往办事器,它也撑持手工设置cookie后发送到办事器端。不幸的是,对若何处置cookie,有几个标准相互抵触:Netscape Cookie 草案, RFC2109, RFC2965,并且还有很大数目的软件商的cookie完成不遵守任何标准. 为了处置这类情况,HttpClient供应了战略驱动的cookie办理体例。HttpClient撑持的cookie标准有:
Netscape cookie草案,是最早的cookie标准,基于rfc2109。虽然这个标准与rc2109有较大的不同,如许做可以与一些办事器兼容。
rfc2109,是w3c宣布的第一个官方cookie标准。实际上讲,一切的办事器在处置cookie(版本1)时,都要遵守此标准,正因如斯,HttpClient将其设为默许的标准。遗憾的是,这个标准太严厉了,乃至良多办事器不准确的实行了该标准或仍在感化Netscape标准。在这类情形下,应利用兼容标准。
兼容性标准,设计用来兼容尽量多的办事器,即便它们并没有遵守尺度标准。当解析cookie呈现成绩时,应思索采取兼容性标准。
RFC2965标准临时没有被HttpClient撑持(在今后的版本为会加上),它界说了cookie版本2,并申明了版本1cookie的缺乏,RFC2965成心有久代替rfc2109.
在HttpClient中,有两种办法来指定cookie标准的利用,
HttpClient client = new HttpClient();
client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
这类办法设置的标准只对以后的HttpState无效,参数可取值CookiePolicy.COMPATIBILITY,CookiePolicy.NETSCAPE_DRAFT或CookiePolicy.RFC2109。
System.setProperty("apache.commons.httpclient.cookiespec", "COMPATIBILITY");
此法指的标准,对今后每一个新创立的HttpState对象都无效,参数可取值"COMPATIBILITY","NETSCAPE_DRAFT"或"RFC2109"。
常有不克不及解析cookie的成绩,但改换到兼容标准大都能处理。
9、利用HttpClient碰到成绩怎样办?
用一个阅读器会见办事器,以确认办事器应对正常
假如在使代办署理,关失落代办署理尝尝
另找一个办事器来尝尝(假如运转着分歧的办事器软件更好)
反省代码是不是按教程中讲的思绪编写
设置log级别为debug,找出成绩呈现的缘由
翻开wiretrace,来追踪客户端与办事器的通讯,以的确成绩呈现在甚么中央
用telnet或netcat手工将信息发送到办事器,合适于猜想已找到了缘由而停止实验时
将netcat以监听体例运转,用作办事器以反省httpclient若何处置应对的。
使用最新的httpclient尝尝,bug能够在最新的版本中修复了
向邮件列表求匡助
向bugzilla呈报bug.
10、SSL
借助Java Secure Socket Extension (JSSE),HttpClient周全撑持Secure Sockets Layer (SSL)或IETF Transport Layer Security (TLS)协定上的HTTP。JSSE已jre1.4及今后的版本中,之前的版本则需求手工装置设置,详细进程拜见Sun网站或本进修笔记。
HttpClient中利用SSL十分复杂,参考上面两个例子:
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());
,假如经由过程需求受权的代办署理,则以下:
HttpClient httpclient = new HttpClient();
httpclient.getHostConfiguration().setProxy("myproxyhost", 8080);
httpclient.getState().setProxyCredentials("my-proxy-realm", " myproxyhost",
new UsernamePasswordCredentials("my-proxy-username", "my-proxy-password"));
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString());
在HttpClient中定制SSL的步调以下:
供应了一个完成了org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory接口的socket factory。这个 socket factory担任打一个到办事器的端口,利用尺度的或第三方的SSL函数库,并停止象毗连握手等初始化操作。凡是情形下,这个初始化操作在端口被创立时主动停止的。
实例化一个org.apache.commons.httpclient.protocol.Protocol对象。创立这个实例时,需求一个正当的协定类型(如https),一个定制的socket factory,和一个默许的端中号(如https的443端口).
Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);
然后,这个实例可被设置为协定的处置器。
HttpClient httpclient = new HttpClient();
httpclient.getHostConfiguration().setHost("www.whatever.com", 443, myhttps);
GetMethod httpget = new GetMethod("/");
httpclient.executeMethod(httpget);
经由过程挪用Protocol.registerProtocol办法,将此定制的实例,注册为某一特定协定的默许的处置器。由此,可以很便利地定制本人的协定类型(如myhttps)。
Protocol.registerProtocol("myhttps",
new Protocol("https", new MySSLSocketFactory(), 9443));
...
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("myhttps://www.whatever.com/");
httpclient.executeMethod(httpget);
假如想用本人定制的处置器代替https默许的处置器,只需求将其注册为"https"便可。
Protocol.registerProtocol("https",
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
httpclient.executeMethod(httpget);
已知的限制和成绩
延续的SSL毗连在Sun的低于1.4JVM上不克不及任务,这是因为JVM的bug形成。
经由过程代办署理会见办事器时,非争先认证( Non-preemptive authentication)会掉败,这是因为HttpClient的设计缺点酿成的,今后的版本中会修正。
碰到成绩的处置
良多成绩,出格是在jvm低于1.4时,是由jsse的装置酿成的。
上面的代码,可作为终究的检测手腕。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import javax.net.ssl.SSLSocketFactory;
public class Test {
public static final String TARGET_HTTPS_SERVER = "www.verisign.com";
public static final int TARGET_HTTPS_PORT = 443;
public static void main(String[] args) throws Exception {
Socket socket = SSLSocketFactory.getDefault().
createSocket(TARGET_HTTPS_SERVER, TARGET_HTTPS_PORT);
try {
Writer out = new OutputStreamWriter(
socket.getOutputStream(), "ISO-8859-1");
out.write("GET / HTTP/1.1rn");
out.write("Host: " + TARGET_HTTPS_SERVER + ":" +
TARGET_HTTPS_PORT + "rn");
out.write("Agent: SSL-TESTrn");
out.write("rn");
out.flush();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} finally {
socket.close();
}
}
}
11、httpclient的多线程处置
利用多线程的次要目标,是为了完成并行的下载。在httpclient运转的过程当中,每一个http协定的办法,利用一个HttpConnection实例。因为毗连是一种无限的资本,每一个毗连在某一时辰只能供一个线程和办法利用,所以需求确保在需求时准确地分派毗连。HttpClient采取了一品种似jdbc毗连池的办法来办理毗连,这个办理任务由 MultiThreadedHttpConnectionManager完成。
MultiThreadedHttpConnectionManager connectionManager =
new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
此是,client可以在多个线程中被用来履行多个办法。每次挪用HttpClient.executeMethod() 办法,城市去链接收理器请求一个毗连实例,请求胜利这个链接实例被签出(checkout),随之在链接利用完后必需偿还办理器。办理器撑持两个设置: maxConnectionsPerHost 每一个主机的最大并行链接数,默许为2
maxTotalConnections 客户端总并行链接最大数,默许为20
办理重视新使用链接时,接纳早偿还者先重用的体例(least recently used approach)。
因为是利用HttpClient的法式而不是HttpClient自己来读取应对包的主体,所以HttpClient没法决意甚么工夫毗连不再利用了,这也就请求在读完应对包的主体后必需手工显式地挪用releaseConnection()来释放请求的链接。
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
...
// 在某个线程中。
GetMethod get = new GetMethod("http://jakarta.apache.org/");
try {
client.executeMethod(get);
// print response to stdout
System.out.println(get.getResponseBodyAsStream());
} finally {
// be sure the connection is released back to the connection
// manager
get.releaseConnection();
}
对每个HttpClient.executeMethod须有一个method.releaseConnection()与之婚配.
12、HTTP办法
HttpClient撑持的HTTP办法有8种,上面分述之。
1、Options
HTTP办法Options用来向办事器发送恳求,但愿取得针对由恳求URL(request url)标记的资本在恳求/应对的通讯进程可使用的功效选项。经由过程这个办法,客户端可以在接纳详细举动之前,便可对某一资本决意接纳甚么举措和/或和一些需要前提,或懂得办事器供应的功效。这个办法最典范的使用,就是用来获得办事器撑持哪些HTTP办法。
HttpClient中有一个类叫OptionsMethod,来撑持这个HTTP办法,使用这个类的getAllowedMethods办法,就能够很复杂地完成上述的典范使用。
OptionsMethod options = new OptionsMethod("http://jakarta.apache.org");
// 履行办法并做响应的异常处置
...
Enumeration allowedMethods = options.getAllowedMethods();
options.releaseConnection();
2、Get
HTTP办法GET用来取回恳求URI(request-URI)标记的任何信息(以实体(entity)的模式),"get"这个单词本意就是”获得“的意思。假如恳求URI指向的一个数据处置进程,那这个进程生成的数据,在应对中以实体的模式被前往,而不是将这个进程的代码的前往。
假如HTTP包中含有If-ModifiedSince, If-Unmodified-Since, If-Match, If-None-Match, 或 If-Range等头字段,则GET也就酿成了”前提GET“,即只要知足上述字段描写的前提的实体才被取回,如许可以削减一些非必须的收集传输,或削减为获得某一资本的屡次恳求(如第一次反省,第二次下载)。(普通的阅读器,都有一个一时目次,用来缓存一些网页信息,当再次阅读某个页面的时分,只下载那些修正过的内容,以加速阅读速度,就是这个事理。至于反省,则经常使用比GET更好的办法HEAD来完成。)假如HTTP包中含有Range头字段,那末恳求URI指定的实体中,只要决意局限前提的那局部才被取回来。(用过量线程下载东西的伴侣,能够对照轻易了解这一点)
这个办法的典范使用,用来从web办事器下载文档。HttpClient界说了一个类叫GetMethod来撑持这个办法,用GetMethod类中getResponseBody, getResponseBodyAsStream 或 getResponseBodyAsString函数就能够取到应对包包体中的文档(如HTML页面)信息。这这三个函数中,getResponseBodyAsStream凡是是最好的办法,次要是由于它可以免在处置下载的文档之前缓存一切的下载的数据。
GetMethod get = new GetMethod("http://jakarta.apache.org");
// 履行办法,并处置掉败的恳求.
...
InputStream in = get.getResponseBodyAsStream();
// 使用输出流来处置信息。
get.releaseConnection();
对GetMethod的最多见的不准确的利用,是未将全体的应对主体的数据读出来。还有,必需注重要手工明白地将链接释放。
3、Head
HTTP的Head办法,与Get办法完整分歧,独一的不同是办事器不克不及在应对包中包括主体(message-body),并且必定不克不及包括主体。利用这个办法,可使得客户无需将资本下载回便可就以失掉一些关于它的根基信息。这个办法经常使用来反省超链的可会见性和资本比来有无被修正。
HTTP的head办法最典范的使用,是获得资本的根基信息。HttpClient界说了HeadMethod类撑持这个办法,HeadMethod类与其它*Method类一样,用 getResponseHeaders()取回头部信息,而没有本人的特别办法。
HeadMethod head = new HeadMethod("http://jakarta.apache.org");
// 履行办法,并处置掉败的恳求.
...
// 取回应对包的头字段信息.
Header[] headers = head.getResponseHeaders();
// 只取回最初修正日期字段的信息.
String lastModified = head.getResponseHeader("last-modified").getValue();
4、Post
Post在英文有“派驻”的意思,HTTP办法POST就是请求办事器承受恳求包中的实体,并将其作为恳求URI的上司资本。从实质上说,这意味着办事器要保留这个实体信息,并且凡是由办事器真个法式停止处置。Post办法的设计意图,是要以一种一致的体例完成以下功效:
对已有的资本做评注
将信息宣布到BBS、旧事组、邮件列表,或相似的文章组中
将一块数据,提交给数据处置历程
经由过程追加操作,来扩大一个数据库
这些都操作等候着在办事器端发生必定的“反作用”,如修正了数据库等。
HttpClient界说PostMethod类以撑持该HTTP办法,在httpclient中,利用post办法有两个根基的步调:为恳求包筹办数据,然后读取办事器来的应对包的信息。经由过程挪用 setRequestBody()函数,来为恳求包供应数据,它可以吸收三类参数:输出流、名值对数组或字符串。至于读取应对包需求挪用 getResponseBody* 那一系列的办法,与GET办法处置应对包的办法不异。
罕见成绩是,未将全体应对读取(不管它对法式是不是有效),或没有释放链接资本。
你发奋努力,熟悉了安全方面的问题,然后又设计了一些程序,感觉还不错。 |
|