• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

unrelentingtech/httpotion: (soft-deprecated) HTTP client for Elixir (use Tesla p ...

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

unrelentingtech/httpotion

开源软件地址:

https://github.com/unrelentingtech/httpotion

开源编程语言:

Elixir 100.0%

开源软件介绍:

hex.pm version hex.pm downloads API Docs Build Status unlicense

HTTPotion

HTTP client for Elixir, based on ibrowse. Continues the HTTPun tradition of HTTParty, HTTPretty, HTTParrot and HTTPie.

Note: unfortunately, ibrowse seems a bit buggy and not super actively maintained. You might want to check out Tesla with hackney instead, and this cert verification setup.

Installation

Add HTTPotion to your project's dependencies in mix.exs:

  defp deps do
    [
      {:httpotion, "~> 3.1.0"}
    ]
  end

  def application do
    [ applications: [:httpotion] ]
    # Application dependency auto-starts it, otherwise: HTTPotion.start
  end

And fetch your project's dependencies:

$ mix deps.get

Usage

Note: You can load HTTPotion into the Elixir REPL by executing this command from the root of your project:

$ iex -S mix

Note: HTTPotion now enables certificate verification by default, using a few default CA bundle paths (/etc/ssl/cert.pem etc.) or the certifi package (which is not a mandatory dependency).

Some basic examples:

iex> response = HTTPotion.get "https://httpbin.org/get"
%HTTPotion.Response{
  body: "{\n…",
  headers: %HTTPotion.Headers{ hdrs: %{"connection" => "keep-alive",} },
  status_code: 200
}

iex> HTTPotion.Response.success?(response)
true

# Response headers are wrapped to allow case-insensitive access (and to support both atoms and strings)
iex> response.headers[:sErvEr]
"meinheld/0.6.1"

iex> response.headers["ConTenT-TyPe"]
"application/json"

# Response headers can have multiple values
iex> response = HTTPotion.get "https://httpbin.org/response-headers?foo=1&foo=2&bar=1"
%HTTPotion.Response{
  body: "{\n…",
  headers: %HTTPotion.Headers{ hdrs: %{"foo" => ["1", "2"], "bar" => "1"} },
  status_code: 200
}

# You can provide a map for the query string
iex> HTTPotion.get("https://httpbin.org/get", query: %{page: 2})
%HTTPotion.Response{body: "…", headers: , status_code: 200}

# Follow redirects
iex> HTTPotion.get("https://httpbin.org/redirect-to?url=http%3A%2F%2Fexample.com%2F", follow_redirects: true)
%HTTPotion.Response{body: "…<title>Example Domain</title>…", headers: , status_code: 200}

# Send form data
iex> HTTPotion.post "https://httpbin.org/post", [body: "hello=" <> URI.encode_www_form("w o r l d !!"),
  headers: ["User-Agent": "My App", "Content-Type": "application/x-www-form-urlencoded"]]
%HTTPotion.Response{body: "…", headers: , status_code: 200}

# Use a custom method
iex> HTTPotion.request :propfind, "http://httpbin.org/post", [body: "I have no idea what I'm doing"]
%HTTPotion.Response{body: "…", headers: , status_code: 405}

# Send Basic auth credentials
iex> HTTPotion.get "https://httpbin.org/basic-auth/foo/bar", [basic_auth: {"foo", "bar"}]
%HTTPotion.Response{
  body: "…",
  headers: %HTTPotion.Headers { hdrs: %{"Access-Control-Allow-Credentials": "true",} },
  status_code: 200
}

# Pass options to ibrowse (note that it usually takes char_lists, not elixir strings)
iex> HTTPotion.get "https://check-tls.akamaized.net", [ ibrowse: [ ssl_options: [ versions, [:'tlsv1.1'] ] ] ]
%HTTPotion.Response{body: "…TLS SNI: present - Check TLS - (https,tls1.1,ipv4)…", headers: , status_code: 200}

# Change the timeout (default is 5000 ms)
iex> HTTPotion.get "https://example.com", [timeout: 10_000]

# If there is an error a `HTTPotion.ErrorResponse` is returned
iex> HTTPotion.get "http://localhost:1"
%HTTPotion.ErrorResponse{message: "econnrefused"}

# You can also raise `HTTPError` with the `bang` version of request
iex> HTTPotion.get! "http://localhost:1"
** (HTTPotion.HTTPError) econnrefused

The Response is a struct, you can access its fields like: response.body.

response.headers is a struct (HTTPotion.Headers) that wraps a map to provide case-insensitive access (so you can use response.headers[:authorization] and it doesn't matter if the server returned AuThOrIZatIOn or something).

HTTPError is an exception that happens when a bang request (request! / get! / …) fails.

Available options and their default values:

{
  body: "",                # Request's body contents, e.g. "{json: \"string\"}"
  headers: [],             # Request's headers, e.g. [Accept: "application/json"]
  query: nil,              # Query string, e.g. %{page: 1}
  timeout: 5000,           # Timeout in milliseconds, e.g. 5000
  basic_auth: nil,         # Basic auth credentials, e.g. {"username", "password"}
  stream_to: nil,          # A process to stream the response to when performing async requests
  direct: nil,             # An ibrowse worker for direct mode
  ibrowse: [],             # ibrowse options
  auto_sni: true,          # Whether TLS SNI should be automatically configured (does URI parsing)
  follow_redirects: false, # Whether redirects should be followed
}

Metaprogramming magic

You can extend HTTPotion.Base to make cool HTTP API wrappers (this example uses Poison for JSON):

defmodule GitHub do
  use HTTPotion.Base

  def process_url(url) do
    "https://api.github.com/" <> url
  end

  def process_request_headers(headers) do
    Dict.put headers, :"User-Agent", "github-potion"
  end

  def process_response_body(body) do
    body |> Poison.decode!
  end
end
iex> GitHub.get("users/myfreeweb").body["public_repos"]
233

Read the source to see all the hooks.

Keep in mind that process_response_body and process_response_chunk get iodata. By default, they call IO.iodata_to_binary. But efficient parsers like Poison can work directly on iodata.

Asynchronous requests

You can get the response streamed to your current process asynchronously:

iex> HTTPotion.get "http://httpbin.org/get", [stream_to: self]
%HTTPotion.AsyncResponse{id: -576460752303419903}

iex> flush
%HTTPotion.AsyncHeaders{
  id: -576460752303419903,
  status_code: 200,
  headers: %HTTPotion.Headers{ hdrs: %{"connection" => "keep-alive",} }
}
%HTTPotion.AsyncChunk{
  id: -576460752303419903,
  chunk: "{\n…"
}
%HTTPotion.AsyncEnd{
  id: -576460752303419903
}

Note that instead of process_response_body, process_response_chunk is called on the chunks before sending them out to the receiver (the stream_to process).

Direct access to ibrowse workers

ibrowse allows you to use its separate worker processes directly. We expose this functionality through the direct option.

Don't forget that you have to pass the URL to the worker process, which means the worker only communicates with one server (domain!)

iex> {:ok, worker_pid} = HTTPotion.spawn_worker_process("http://httpbin.org")

iex> HTTPotion.get "httpbin.org/get", [direct: worker_pid]
%HTTPotion.Response{body: "…", headers: ["Connection": "close",], status_code: 200}

You can even combine it with async!

iex> {:ok, worker_pid} = HTTPotion.spawn_worker_process("http://httpbin.org")

iex> HTTPotion.post "httpbin.org/post", [direct: worker_pid, stream_to: self, headers: ["User-Agent": "hello it's me"]]
%HTTPotion.AsyncResponse{id: {1372,8757,656584}}

Type analysis

HTTPotion contains typespecs so your usage can be checked with dialyzer, probably via dialyxir or elixir-ls.

HTTPotion's tests are checked with dialyxir.

Contributing

Please feel free to submit pull requests!

By participating in this project you agree to follow the Contributor Code of Conduct.

The list of contributors is available on GitHub.

License

This is free and unencumbered software released into the public domain.
For more information, please refer to the UNLICENSE file or unlicense.org.




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap