技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 其他 --> Clojure世界:Http Client

Clojure世界:Http Client

浏览:1983次  出处信息
    使用http client提交表单或者下载网页也是非常常见的任务,比如使用Java的时候可以用标准库的HttpURLConnection,也可以选择Apache Http Client。在clojure里也有这样的类库,这里我将介绍三个各有特色的http client实现。

    首先,我最先推荐使用clj-http这个类库,它是Apache HttpClient的clojure wrapper,是一个提供同步API的简单易用的Http Client。

名称: clj-http
主页:https://github.com/dakrone/clj-http
依赖:
[clj-http "0.3.1"]

例子:
(require '[clj-http.client :as client])
(client/get "http://google.com")
结果:
=> {:cookies {"NID" {:domain ".google.com.hk", :expires #<Date Tue Aug 14 18:20:38 CST 2012>, :path "/", :value "56=qn2OWtODE2D3fUKi_vbi44jZepOeLI9xC4Ta1JQLEicqUvIZAqr7TCmft_hq8i_FRwnFXdTK1jV2S5IrSZFyYhlAN2KcQEXgWX1iK36gM2iYPaKPihuUZDCqgiAamDOl", :version 0}, "PREF" {:domain ".google.com.hk", :expires #<Date Wed Feb 12 18:20:38 CST 2014>, :path "/", :value "ID=8b73a654ff0a2783:FF=0:NW=1:TM=1329128438:LM=1329128438:S=uEM4SsFuHlkqtVhp", :version 0}},
    :status 
200

    :headers {
"date" "Sun, 01 Aug 2010 07:03:49 GMT"
              
"cache-control" "private, max-age=0"
              
"content-type" "text/html; charset=ISO-8859-1"
              }
    :body 
"<!doctype html>"
    :trace
-redirects ["http://google.com" "http://www.google.com/" "http://www.google.fr/"]}
更多例子:
(client/get "http://site.com/resources/3" {:accept :json})

;; Various options:
(client
/post "http://site.com/api"

  {:basic
-auth ["user" "pass"]
   :body 
"{\"json\": \"input\"}"

   :headers {
"X-Api-Version" "2"}
   :content
-
type :json
   :socket
-timeout 1000

   :conn
-timeout 1000
   :accept :json})

;; Need to contact a server with an untrusted SSL cert
?
(client
/get "https://alioth.debian.org" {:insecure? true})

;; If you don
't want to follow-redirects automatically:

(client/get "http://site.come/redirects-somewhere" {:follow-redirects false})

;; Only follow a certain number of redirects:
(client
/get "http://site.come/redirects-somewhere" {:max-redirects 5
})

;; Throw an exception 
if
 redirected too many times:
(client
/get "http://site.come/redirects-somewhere" {:max-redirects 5 :throw-exceptions true
})

;; Send form params as a urlencoded body
(client
/post "http//site.com" {:form-params {:foo "bar"
}})

;; Multipart form uploads
/
posts
;; a map or vector works as the multipart object. Use a vector of
;; vectors 
if
 you need to preserve order, a map otherwise.
(client
/post "http//example.org" {:multipart [["title" "My Awesome Picture"
]
                                              [
"Content/type" "image/jpeg"
]
                                              [
"file" (clojure.java.io/file "pic.jpg"
)]]})
;; Multipart values can be one of the following:
;; String, InputStream, File, or a 
byte-
array

;; Basic authentication
(client
/get "http://site.com/protected" {:basic-auth ["user" "pass"
]})
(client
/get "http://site.com/protected" {:basic-auth "user:pass"
})

;; Query parameters
(client
/get "http://site.com/search" {:query-params {"q" "foo, bar"}})

    clj-http的API相当的简洁漂亮,使用起来非常便利,强烈推荐。题外,学习clojure的一个好方法就是为现有的java类库实现一些方便的clojure wrapper。

    如果你需要异步的http client,我会推荐http.async.client这个类库,它的API是异步形式的类似 Java的Future模式,对于clojure程序员来说应该更像是agent。

名称:http.async.client
主页:https://github.com/neotyk/http.async.client
依赖:
[http.async.client "0.4.1"]
例子:
(require '[http.async.client :as c])
(with-open [client (c/create-client)]
  (let [response (c
/GET client "http://neotyk.github.com/http.async.client/"
)]
    (prn (c
/done?
 response))
    (c
/
await response)
    (prn (c
/
string response))
    (prn (c
/
status response))
    (prn (c
/done? response))))

输出:
false
<!DOCTYPE html 
{:code 
200, :msg "OK", :protocol "HTTP/1.1", :major 1, :minor 1
}
true

更多例子:
(c/POST client "http://example.com" :body "hello world" :timeout 3000)
(c
/DELETE client "http://example.com"
)
(c
/POST client "http://example.com" :body "hello world" :auth {:type :basic :user "admin" :password "admin"})

请注意,这些方法都是异步调用的,你需要通过await来等待调用完成,或者通过done?来判断调用是否完成。
http.async.client有个比较重要的特性就是对Http Chunked编码的支持,分别通过LazySeq和callback的方式支持,首先看将Http chunked变成一个lazy seq:

(with-open [client (client/create-client)] ; Create client
  (let [resp (client
/stream-
seq client :get url)]
    (doseq [s (s
/
string resp)]
      (println s))))

这里非常关键的一点是stream-seq返回的chunk序列,每取一个就少一个(通过first函数),也就是说每次调用first取到的chunk都不一样,是顺序递增,不可重复获取的。

通过callback方式处理:
(with-open [client (client/create-client)] ; Create client
  (let [parts (ref #{})
        resp (client
/request-
stream client :get url
                                    (fn [state body]
                                      (dosync (alter parts conj (string body)))
                                      [body :
continue
]))]
    ;; 
do
 something to @parts
    ))
自己传入一个callback函数接收chunk,比如这里用一个ref累积。

http.async.client的详细文档看这里:http://neotyk.github.com/http.async.client/docs.html

最后,有兴趣还可以看下aleph这个异步通讯的框架,它支持Http协议,也提供了http server和client的实现。不过它的API就没有那么简单明了,它的模型是类似go语言里利用channel做异步通讯的模型,http只是它的一个模块罢了,这是另一个话题了。

建议继续学习:

  1. Clojure世界:XML处理    (阅读:1979)
  2. Clojure世界:文件IO    (阅读:1861)
  3. Clojure世界:如何做性能测试    (阅读:1743)
  4. Clojure世界:API文档生成    (阅读:1648)
  5. Clojure世界:使用rlwrap增强REPL    (阅读:1566)
  6. Clojure世界:静态代码分析    (阅读:1632)
  7. Clojure世界:单元测试    (阅读:1464)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1