Documentation
¶
Overview ¶
Package reader は、HTTP/HTTPS や GCS/S3 など URI の種類を問わず コンテンツを読み込み、必要に応じて内容を抽出するユニバーサルリーダーを提供します。
Index ¶
- Constants
- Variables
- type ContentTypeExtractor
- type Extractor
- type HTTPClient
- type Option
- func WithExtractor(extractor Extractor) Option
- func WithGCSFactory(fn StorageFactory) Option
- func WithHTTPClient(client HTTPClient) Option
- func WithMaxRetries(n uint) Option
- func WithRetryInterval(initialInterval, maxInterval time.Duration) Option
- func WithS3Factory(fn StorageFactory) Option
- func WithSafeURLValidator(fn SafeURLValidator) Option
- type RetryClassifier
- type SafeURLValidator
- type StorageFactory
- type UniversalReader
Examples ¶
Constants ¶
const ( // DefaultMaxRetries は HTTP 取得を再試行する既定の回数です(初回の実行を含みません)。 DefaultMaxRetries = 2 // DefaultRetryInitialInterval は再試行までの初期待機時間です。 DefaultRetryInitialInterval = 500 * time.Millisecond // DefaultRetryMaxInterval は再試行までの待機時間の上限です。 DefaultRetryMaxInterval = 4 * time.Second )
リトライの既定値です。httpkit の既定(初期 5 秒・最大 30 秒)より短くしています。 Open は呼び出し側を待たせる同期 API なので、待ち時間の合計が体感を直接左右します。
Variables ¶
var ErrClosed = errors.New("reader is closed")
ErrClosed は、Close 済みの UniversalReader を使おうとしたことを表します。
Functions ¶
This section is empty.
Types ¶
type ContentTypeExtractor ¶ added in v1.4.0
type ContentTypeExtractor interface {
ExtractWithContentType(ctx context.Context, r io.Reader, contentType string) (text string, hasBody bool, err error)
}
ContentTypeExtractor は、Content-Type ヘッダーも受け取れる抽出器です。
別の口ではなく、WithExtractor に渡した抽出器が追加で持てる能力です。 満たしていれば Extract の代わりにこちらが呼ばれます。
文字コードの変換は <meta charset> を読める抽出器側の 1 箇所でしか行えないため (UTF-8 に直したバイト列を再度 Shift_JIS と解釈すれば壊れます)、 reader は Content-Type を判定材料として渡すだけで変換はしません。
type Extractor ¶
type Extractor interface {
Extract(ctx context.Context, r io.Reader) (text string, hasBody bool, err error)
}
Extractor は取得済みの HTML から本文テキストを抽出します。 第2戻り値は本文が見つかったかどうかです。
type HTTPClient ¶
HTTPClient は HTTP リクエストを実行する最小インターフェースです。
type Option ¶
type Option func(*options)
Option は UniversalReader の依存を差し替えるためのオプションです。
nil の Option、および nil の値を渡した With* は無視され、既定値が保たれます。 差し替えたつもりで既定のまま動くので、渡す値が nil でないことは呼び出し側で確かめてください。
func WithExtractor ¶
WithExtractor はテキスト抽出器を差し替えます。 HTTP の取得そのものは差し替わりません(そちらは WithHTTPClient)。
抽出器が ContentTypeExtractor も満たす場合は、Content-Type ヘッダーを添えて 呼ばれます(既定の extract.Engine は満たします)。
func WithGCSFactory ¶
func WithGCSFactory(fn StorageFactory) Option
WithGCSFactory は GCS ファクトリ生成処理を差し替えます。
func WithHTTPClient ¶
func WithHTTPClient(client HTTPClient) Option
WithHTTPClient は HTTP(S) の取得に使うクライアントを差し替えます。
リクエストヘッダーを変えたい場合もここです。Do の中で *http.Request を 書き換えてから元のクライアントに委譲してください。
レスポンスサイズの上限は外れません。上限はクライアントの外側(返ってきた *http.Response を読み切る go-http-kit の処理)で掛かるためです。
func WithMaxRetries ¶ added in v1.4.0
WithMaxRetries は HTTP 取得を再試行する回数を設定します(初回の実行は含みません)。 0 を渡すと再試行しません。
再試行するのは 5xx / 408 / 429 と、分類できない通信エラー(タイムアウトなど)だけです。 4xx やレスポンスサイズ超過は、同じリクエストを繰り返しても結果が変わらないため再試行しません。
レスポンスに Retry-After があった場合、次の待機時間は指数バックオフの算出値ではなく その指示値になります(WithRetryInterval で設定した間隔は使われません)。 サーバーが待てと言った時間より早く送り直しても、同じ拒否が返るだけだからです。
既定のクライアントを WithHTTPClient で自前のリトライ付きクライアントに 差し替える場合は、二重に待たないよう 0 を渡してください。
func WithRetryInterval ¶ added in v1.4.0
WithRetryInterval は再試行までの待機時間(指数バックオフの初期値と上限)を設定します。 0 以下の値は無視され、既定値が保たれます。
func WithS3Factory ¶
func WithS3Factory(fn StorageFactory) Option
WithS3Factory は S3 ファクトリ生成処理を差し替えます。
func WithSafeURLValidator ¶
func WithSafeURLValidator(fn SafeURLValidator) Option
WithSafeURLValidator は URL 安全性検証関数を差し替えます。
検証器が呼ばれるのは HTTP(S) の枝だけです。gs:// / s3:// は接続先をクラウド SDK が 決めるため検証を通らず、ストレージ側の URI を弾く口ではありません。
ローカルのテストサーバーへ向けるなら WithHTTPClient も差し替えてください。 検証器だけ緩めても、既定のクライアントが接続直前に行う IP 検証で落ちます。
type RetryClassifier ¶ added in v1.4.0
RetryClassifier は、取得の失敗を再試行すべきか判断できる HTTP クライアントです。 HTTPClient が満たしていればその判断を優先します。エラーの型を知っているのは それを返したクライアントなので、リトライ対象の定義を reader 側で二重管理しません。
type SafeURLValidator ¶
SafeURLValidator は URI の安全性を検証します。安全な場合は nil を返します。 名前解決を伴うため context を受け取ります。
type StorageFactory ¶
StorageFactory は GCS/S3 のクライアント一式を生成します。 実際の接続確立を伴うため、対象スキームの初回 Open 時にだけ呼ばれます。
type UniversalReader ¶
type UniversalReader struct {
// contains filtered or unexported fields
}
UniversalReader は URI の種類に応じて読み取りストリームを返します。
func New ¶
func New(opts ...Option) *UniversalReader
New は UniversalReader の新しいインスタンスを生成します。
エラーを返さないのは、ここで確立する外部接続がないためです。GCS/S3 の クライアントは対象スキームの初回 Open まで作られず、失敗するとしたらそちらです。
func (*UniversalReader) Close ¶
func (r *UniversalReader) Close() error
Close は内部で保持している外部リソースを解放します。 Close は終端です。スキームを問わず、解放後の Open は ErrClosed を返します。
func (*UniversalReader) Open ¶
func (r *UniversalReader) Open(ctx context.Context, uri string) (io.ReadCloser, error)
Open は URI のスキームを判別し、適切な読み取りストリームを返します。
扱えるのは https:// / http:// / gs:// / s3:// の 4 つで、それ以外は 「未対応のURIスキームです」を返します。ローカルファイルパスは対象外です。
スキームは小文字で書かれている必要があります。判定は "://" の前をそのまま 文字列比較するだけで、url.Parse と違って大文字小文字を正規化しないため、 HTTPS:// のような大文字のスキームは未対応として扱われます。
gs:// / s3:// はストリームを返しますが、HTTP(S) は本文抽出と再試行のために レスポンスを読み切ってから返します。返ったストリームを少しずつ読んでも メモリは節約になりません(上限は go-http-kit のレスポンスサイズ上限です)。
func (*UniversalReader) ReadAll ¶ added in v1.4.0
ReadAll は URI の内容を最後まで読み込んで返します。 Open したストリームを読み切って閉じるまでを畳んだもので、閉じ忘れを防ぎます。
Example ¶
ネットワークに出るため Output は付けていません(コンパイルだけ行われます)。
package main
import (
"context"
"fmt"
"github.com/shouni/go-web-reader/reader"
)
func main() {
r := reader.New()
defer func() { _ = r.Close() }()
body, err := r.ReadAll(context.Background(), "https://example.com/article")
if err != nil {
panic(err)
}
fmt.Println(string(body))
}
Output: