まずはreqwest
クレートを使ってウェブページを取得するコードを書いてみましょう。最初は使い勝手を確かめるためにsrc/main.rs
に直に書いていくことにします。reqwest
クレートにどんな機能があるかを知るために、 Docs.rs にあるドキュメントを見てみましょう。
最初に目に入ってくる文章をざっと読むと、reqwest
クレートは非同期なHTTPクライアントとブロックする(つまり送信や受信を行う関数を呼び出すと、処理が完了するまで戻ってこない)HTTPクライアントの機能を提供していることが分かります。今回は非同期プログラミングは必要ないので、ブロックするクライアントを使うことにしましょう。
サンプルコードを動かす
reqwest::blocking
モジュールのドキュメントを開きます。ドキュメントの"§Making a GET request"に書かれたサンプルコードをひとまずコンパイルできるようにしてしまいます。
Cargo.toml
のdependencies
セクションにreqwest
への依存を書きます。ドキュメントにはblocking
featureを有効にする必要があると書かれているので以下の記述を追加します。また、main
関数で?
演算子を使いたいのでエラーハンドリングのためにeyre
クレートへの依存も宣言します。
[dependencies]
reqwest = { version = "0.10.8", features = ["blocking"] }
eyre = "0.6"
reqwest::blocking
モジュールのサンプルコードをmain
関数の中に貼り付けて、プログラムが動作するようにコードを書き足したものが以下のソースコードになります。main
関数の戻り値をResult
型にすることで?
演算子を使ってエラーを返すことができるようになります。std::result::Result<T, E>
を使うとE
に適切な型を入れる必要があるので、ここでは簡単に済ませるためにeyre::Result<T>
を使いました。eyre::Result<T>
を使うことでエラーがBox<dyn std::error::Error>
のように振る舞う型に自動で変換されます。
fn main() -> eyre::Result<()> {
let body = reqwest::blocking::get("https://www.rust-lang.org")?
.text()?;
println!("body = {:?}", body);
Ok(())
}
これでcargo run
を実行すればコンパイルされた後にプログラムが実行されて、HTMLが出力される様子が見られるでしょう。(ちなみにWiFiをオフにするかEthernetケーブルを抜くかして、インターネットへの疎通がない状態にしてからcargo run
を実行してみましょう。エラーメッセージが表示されるはずです。)
ソースコードの読解
ソースコードを読んでいきましょう。まず、reqwest::blocking::get
関数を呼び出しています。この関数はreqwest::IntoUrl
トレイトを実装した型を引数とする関数です。Url
自身と&str
型と&String
型がこのトレイトを実装します[1]。URLではない文字列が与えられるとエラーを返します。
このサンプルコードを読むと、プロトコルがHTTPなのか、あるいはHTTPSなのかはプログラマは気にしなくていいことがわかります。HTTPとHTTPSで通信をするのに必要な処理は異なりますが、そのあたりはreqwest
が適切にやってくれるようです。
さて、get
関数の戻り値の型はResult<Response>
です。このResult
はreqwest::Result
のことです。エラー型にはreqwest
が定義しているreqwest::Error
が入っています。エラーについては飛ばしてResponse
について調べることにしましょう。
Response
のドキュメントを開きましょう。Response
にはいろいろとメソッドが定義されていますが、今回呼び出しているtext
メソッドのドキュメントを読んでみます。text
メソッドの戻り値の型はResult<String>
です。説明を読むとレスポンスボディをヘッダで指定されたエンコーディングに従ってデコードして返すようです。
最後にeyre::Result<T>
について説明しておきましょう。この型はResult<T, eyre::Report>
として定義されています。eyre::Report
はError + Send + Sync + 'static
を実装したオブジェクトから作ることができます。さまざまな型のエラーを一つの型に変換することで、最終的にプログラムが報告するエラーの取り扱いを容易にすることと、バックトレースを提供するのがeyre::Report
の役目です。
この章で作成したファイル
演習
- インターネットへの疎通がない状態でプログラムを実行してエラーが出るか確かめてみましょう。
-
get
関数に渡すURLをUTF-8以外でエンコーディングされているウェブページにしてプログラムを動かしてみましょう。例えば https://www.hmv.co.jp/ はShift-JISでエンコードされていて、Content-Type
ヘッダで文字コードが指定されています。
(reqwest
はContent-Type
ヘッダで文字コードが指定されていない場合はUTF-8と仮定してボディを読み込みます。http://abehiroshi.la.coocan.jp/ はShift-JISでエンコードされたページですが、Content-Type
ヘッダがありません。) -
get
関数に渡すURLを存在しないページを指すURLにしてみましょう。このとき、レスポンスのステータスコードも表示するようにしてみましょう。(ステータスコードはResponse
構造体のstatus
メソッドで取得することができます。)