Пакет google

Функция google.Search выполняет HTTP-запрос в Google Web Search API и анализирует результат, закодированный в JSON. Он принимает параметр Context ctx и немедленно возвращается, если ctx.Done закрыт, пока запрос отправляется.

Запрос Google Web Search API включает в себя поисковый запрос и IP-адрес пользователя в качестве параметров запроса:

func Search(ctx context.Context, query string) (Results, error) {
    // Подготовка Google Search API запроса.
    req, err := http.NewRequest("GET", "https://ajax.googleapis.com/ajax/services/search/web?v=1.0", nil)
    if err != nil {
        return nil, err
    }
    q := req.URL.Query()
    q.Set("q", query)

    // Если ctx содержит IP-адрес пользователя, его перенаправляет на сервер.
    // Google APIs использует IP-адрес пользователя, чтобы отличать запросы, 
    // инициированные сервером, от запросов конечных пользователей.
    if userIP, ok := userip.FromContext(ctx); ok {
        q.Set("userip", userIP.String())
    }
    req.URL.RawQuery = q.Encode()

Search использует вспомогательную функцию, httpDo, для выдачи HTTP-запроса и отмены, если ctx.Done закрыт во время обработки запроса или ответа. Search передает сигнал закрытия в httpDo для обработки HTTP-ответа:

    var results Results
    err = httpDo(ctx, req, func(resp *http.Response, err error) error {
        if err != nil {
            return err
        }
        defer resp.Body.Close()

        // Разбор JSON результатов поиска.
        // https://developers.google.com/web-search/docs/#fonje
        var data struct {
            ResponseData struct {
                Results []struct {
                    TitleNoFormatting string
                    URL               string
                }
            }
        }
        if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
            return err
        }
        for _, res := range data.ResponseData.Results {
            results = append(results, Result{Title: res.TitleNoFormatting, URL: res.URL})
        }
        return nil
    })
    // httpDo ждет закрытия, которое мы предоставили для возврата, 
    // так что здесь можно безопасно считывать результаты.
    return results, err

Функция httpDo запускает HTTP-запрос и обрабатывает его ответ в новой версии goroutine. Он отменяет запрос, если ctx.Done закрылся до выхода goroutine:

func httpDo(ctx context.Context, req *http.Request, f func(*http.Response, error) error) error {
    // Запустк HTTP-запроса в goroutine и передача ответа в f.
    tr := &http.Transport{}
    client := &http.Client{Transport: tr}
    c := make(chan error, 1)
    go func() { c <- f(client.Do(req)) }()
    select {
    case <-ctx.Done():
        tr.CancelRequest(req)
        <-c // Ожидает пока не вернется f.
        return ctx.Err()
    case err := <-c:
        return err
    }
}

results matching ""

    No results matching ""