java.net.HttpURLConnection 的设计引起的事件
来源:互联网 发布:linux开机自启动设置 编辑:程序博客网 时间:2024/06/05 05:26
以下的内容,我抽空会翻译程中文的,先大家将就着看代码吧!
JavaでHTTPクライアントを作ろうと思ったときには、おそらく二つくらいのアプローチがあって、ひとつがApacheJakartaプロジェクトのHTTPClientを使う方法、もうひとつがjava.net.HttpURLConnection を使う方法だ。まあもちろん、自前でTCPクライアントの上に乗せてもいいのだが、そんな車輪の再発明するくらいならもっと別のことに労力を使うべきだと思う。
というわけで、そのうちひとつのjava.net.HttpURLConnectionの件。HTTPは最初だけ大文字、後小文字の癖に、URLは全部大文字というよくわからんネーミングセンスについてはとりあえず置いておくとして、設計的によくわからないというか、何がしたいのか意味が不明なところがあるのでそれについて書く。
http://java.sun.com/j2se/1.5.0/docs/api/java/net/HttpURLConnection.html
HttpURLConnectionは、URLオブジェクトからコネクションを張ることで以下のように接続を行う。
URL url = new URL("http://example.com/"); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.connect();
で、その後データを取得する。この際使用するのがBufferedReaderなのはバイナリが帰ってくるかもしれないから仕方ない。
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
問題なのは、この
conn.getInputStream()
が、throw IOExceptionとなっていることなのだ。これはリファレンスによれば、
if an I/O error occurs while creating the inputstream.
と書いてある。これ、実際にどういうときに起きるかといえば、他にもあるかもしれないがサーバがエラーを返したときなのだ。つまり、サーバが4xxまたは5xxのエラーレスポンスを返したときには、なぜかInputStreamは生成されない。nullが返るのではなくてExceptionが飛んでくる。そしてその場合にはgetErrorStream()で取得したStreamにHTTPResponseのBodyが返ってくる。
あるサンプルソースコードはこのため、こんなことをやっている(http://java.sun.com/j2se/1.5.0/docs/guide/net/http-keepalive.html)。
try {URL a = new URL(args[0]);URLConnection urlc = a.openConnection();is = conn.getInputStream();int ret = 0;while ((ret = is.read(buf)) > 0) { processBuf(buf);}// close the inputstreamis.close();} catch (IOException e) {try {respCode = ((HttpURLConnection)conn).getResponseCode();es = ((HttpURLConnection)conn).getErrorStream();int ret = 0;// read the response bodywhile ((ret = es.read(buf)) > 0) {processBuf(buf);}// close the errorstreames.close();} catch(IOException ex) {// deal with the exception}}
このソースコードは、まあ目的が違って永続セッションを張ろうとしているので(サーバがエラーを返した時点で終了するのがクライアントとして正しい動作なので)これでいいのだろうけども、「とりあえずInputStreamを取得して、Exceptionが出たらErrorStream使おう」とかいう態度はどうかと思う。例外は、正常形で投げられてはいけないのだ。
HTTPClientを書こうとした人間が、サーバの4xxエラーまたは5xxエラーを正常系とみなすか異常系とみなすかは不明である。サーバにとって異常系なのは明らかだが、例えばサーバのエラーやリンク切れを発見するテストクライアントであれば、異常系ではない。
4xxや5xxがクライアントにとっても異常系だと主張するにしても、getInputStream()で例外を投げるのはタイミングがおかしい。エラーはbodyを取得する前にわかっているのだから、その前に例外を投げるべきだ。
あるいは、以下のような実装も考えられる。
conn.connect(); InputStream stream; if(conn.isSuccess()){ stream = conn.getInputStream(); }else{ stream = conn.getErrorStream(); }
しかし、isSuccessのようなメソッドは実装されていない。また、本質的な話としてこのHttpURLConnection#getInputStreamが例外を投げるケースはResponse Codeが何番なのかということはドキュメントのどこにも書いていないことが挙げられる。したがって、このようなisSuccessを自前で作ることすらできないのだ。
実際に正しくやろうと思ったら現状では以下のようにするしかないが、これで正しいかどうかは誰も保障してくれないのだ。
InputStream stream; int responseCode = conn.getResponseCode(); if(responseCode / 100 == 4 || responseCode / 100 == 5){ stream = conn.getErrorStream(); }else{ stream = conn.getInputStream(); }
明らかに設計ミスだと思うんですが。
- java.net.HttpURLConnection 的设计引起的事件
- java.net.HttpURLConnection的使用
- java.net.HttpURLConnection的使用
- java.net.HttpURLConnection的使用
- java.net.HttpURLConnection的使用
- 【Java】java.net.HttpURLConnection的使用
- 『转』【Java】java.net.HttpURLConnection的使用
- HttpURLConnection 中参数的构建方式 引起的 500错误
- onchanged事件引起的问题
- 键盘引起的事件处理
- 引起进程撤销的事件
- HttpClient4引起的java.net.SocketException: Connection reset解决方法
- .net事件机制使用的设计模式
- Java的HttpURLConnection使用记录
- java.net.HttpURLConnection 实例
- 异步事件引起的plugins crash问题
- 一个fork引起的“穿越”事件。
- 端口单双工模式引起的事件
- ubuntu 下配置jdk详细步骤
- int( (LONG)(LONG_PTR)&(((type *)0)->field))的最好解释
- 分区表及分区索引(7.2)--怎样管理
- Fix "\\computer is not accessible. You might not have permission to use this network resource”
- hdu_2003_求绝对值
- java.net.HttpURLConnection 的设计引起的事件
- OpenNMS全接触-系统架构(三)
- 梦想就在前方 --考研计划
- convert cast
- 计时器 Timer,计时任务 TimerTask
- OpenCV学习笔记(二十二)——粒子滤波跟踪方法
- 8个用于图片展示的jQuery插件及教程推荐
- EBS 表后缀的含义
- hdu_2004_成绩转换