Spec-Zone.ru › Nim

std/httpclient

SourceEdit

Этот модуль реализует простой HTTP-клиент, который можно использовать для получения веб-страниц и других данных.

Предупреждение: Проверьте ненадежные входные данные: парсеры и получатели URI не обнаруживают вредоносные URI.

Получение веб-сайта

В этом примере используется HTTP GET для получения http://google.com:

import std/httpclient
var client = newHttpClient()
try:
  echo client.getContent("http://google.com")
finally:
  client.close()

То же действие можно выполнить асинхронно, просто используйте AsyncHttpClient:

import std/[asyncdispatch, httpclient]

proc asyncProc(): Future[string] {.async.} =
  var client = newAsyncHttpClient()
  try:
    return await client.getContent("http://google.com")
  finally:
    client.close()

echo waitFor asyncProc()

Функциональность, реализованная HttpClient и AsyncHttpClient, одинаковая, поэтому вы можете использовать ту, которая вам больше подходит в показанных здесь примерах.

Примечание: Вам необходимо запускать асинхронные примеры в асинхронной процедуре, иначе вы получите ошибку Undeclared identifier: 'await'.

Примечание: Экземпляр асинхронного клиента может обрабатывать только один запрос за раз. Чтобы отправить несколько запросов параллельно, используйте несколько экземпляров клиента.

Использование HTTP POST

Этот пример демонстрирует использование W3 HTML Validator, он использует multipart/form-data в качестве Content-Type для отправки HTML для валидации на сервер.

var client = newHttpClient()
var data = newMultipartData()
data["output"] = "soap12"
data["uploaded_file"] = ("test.html", "text/html",
  "<html><head></head><body><p>test</p></body></html>")
try:
  echo client.postContent("http://validator.w3.org/check", multipart=data)
finally:
  client.close()

Чтобы передавать файлы с диска при выполнении запроса, используйте addFiles.

Примечание: Это будет выделять новую базу данных Mimetypes каждый раз, когда вы ее вызываете; вы можете передать свою собственную через параметр mimeDb чтобы этого избежать.

let mimes = newMimetypes()
var client = newHttpClient()
var data = newMultipartData()
data.addFiles({"uploaded_file": "test.html"}, mimeDb = mimes)
try:
  echo client.postContent("http://validator.w3.org/check", multipart=data)
finally:
  client.close()

Вы также можете отправлять запросы POST с настраиваемыми заголовками. В этом примере устанавливается Content-Type в application/json и используется json-объект для тела

import std/[httpclient, json]

let client = newHttpClient()
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
let body = %*{
    "data": "some text"
}
try:
  let response = client.request("http://some.api", httpMethod = HttpPost, body = $body)
  echo response.status
finally:
  client.close()

Отчёт о ходе выполнения

Вы можете указать процедуру обратного вызова, которая будет вызываться во время HTTP-запроса. Этот обратный вызов будет выполняться каждую секунду с информацией о ходе выполнения HTTP-запроса.

import std/[asyncdispatch, httpclient]

proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} =
  echo("Downloaded ", progress, " of ", total)
  echo("Current rate: ", speed div 1000, "kb/s")

proc asyncProc() {.async.} =
  var client = newAsyncHttpClient()
  client.onProgressChanged = onProgressChanged
  try:
    discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test")
  finally:
    client.close()

waitFor asyncProc()

Если вы хотите удалить обратный вызов, просто установите его в nil.

client.onProgressChanged = nil
Предупреждение: Значение total , сообщаемое httpclient, может быть 0 в некоторых случаях.

Поддержка SSL/TLS

Для этого требуется библиотека OpenSSL. К счастью, она широко используется и установлена на многих операционных системах. httpclient будет автоматически использовать SSL, если вы передадите любую из функций URL со схемой https, например: https://github.com/.

Вам также необходимо скомпилировать с ssl заданным так: nim c -d:ssl ....

Проверка сертификата выполняется по умолчанию.

Сканируется набор каталогов и файлов из модуля ssl_certs для поиска сертификатов CA.

Пример настройки параметров проверки SSL в новом клиенте:

import httpclient
var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer))

Существует три варианта режима проверки:

  • CVerifyNone: сертификаты не проверяются;
  • CVerifyPeer: сертификаты проверяются;
  • CVerifyPeerUseEnvVars: сертификаты проверяются, и также используются необязательные переменные среды SSL_CERT_FILE и SSL_CERT_DIR для поиска сертификатов

См. newContext для настройки или отключения проверки сертификатов.

Таймауты

В настоящее время таймаут поддерживается только для синхронных функций. Таймаут измеряется в миллисекундах; после его установки любой вызов сокета, который может заблокироваться, будет подвержен этому таймауту.

Может показаться удивительным, но функция в целом может занимать больше времени, чем указанный таймаут; только отдельные внутренние вызовы сокета затронуты. На практике это означает, что пока сервер отправляет данные, исключение не будет сгенерировано, однако, если данные не достигнут клиента в течение указанного таймаута, будет сгенерировано исключение TimeoutError.

Вот как установить таймаут при создании экземпляра HttpClient:

import std/httpclient

let client = newHttpClient(timeout = 42)

Прокси

Прокси можно указать как параметр любой из процедур, определенных в этом модуле. Для этого используйте конструктор newProxy. К сожалению, в настоящее время поддерживается только базовая аутентификация.

Некоторые примеры настройки прокси для HttpClient:

import std/httpclient

let myProxy = newProxy("http://myproxy.network")
let client = newHttpClient(proxy = myProxy)

Использование прокси с базовой аутентификацией:

import std/httpclient

let myProxy = newProxy("http://myproxy.network", auth="user:password")
let client = newHttpClient(proxy = myProxy)

Получение URL прокси из переменных среды:

import std/httpclient

var url = ""
try:
  if existsEnv("http_proxy"):
    url = getEnv("http_proxy")
  elif existsEnv("https_proxy"):
    url = getEnv("https_proxy")
except ValueError:
  echo "Unable to parse proxy from environment variables."

let myProxy = newProxy(url = url)
let client = newHttpClient(proxy = myProxy)

Перенаправления

Максимальное количество перенаправлений можно установить с помощью параметра maxRedirects типа int. Он определяет максимальное количество перенаправлений, которые следует отслеживать; по умолчанию он равен 5, вы можете установить его в 0 для отключения перенаправлений.

Здесь вы можете увидеть пример установки параметра maxRedirects для HttpClient:

import std/httpclient

let client = newHttpClient(maxRedirects = 0)

Импорты

since, net, strutils, uri, parseutils, base64, os, mimetypes, math, random, httpcore, times, tables, streams, monotimes, asyncnet, asyncdispatch, asyncfile, nativesockets

Типы

AsyncHttpClient = HttpClientBase[AsyncSocket]
Source Edit
AsyncResponse = ref object
  version*: string
  status*: string
  headers*: HttpHeaders
  bodyStream*: FutureStream[string]
Source Edit
HttpClient = HttpClientBase[Socket]
Source Edit
HttpClientBase[SocketType] = ref object
  ## Where we are currently connected.
  headers*: HttpHeaders      ## Headers to send in requests.
  ## Maximum redirects, set to `0` to disable.
  timeout*: int              ## Only used for blocking HttpClient for now.
  ## `nil` or the callback to call when request progress changes.
  when SocketType is Socket:
    onProgressChanged*: ProgressChangedProc[void]
  else:
    onProgressChanged*: ProgressChangedProc[Future[void]]
  when defined(ssl):
  when SocketType is AsyncSocket:
  else:
  ## When `false`, the body is never read in requestAux.
Source Edit
HttpRequestError = object of IOError
Выбрасывается в процедуре getContent и postContent при получении от сервера ошибки Source Edit
MultipartData = ref object
Source Edit
MultipartEntries = openArray[tuple[name, content: string]]
Source Edit
ProgressChangedProc[ReturnType] = proc (total, progress, speed: BiggestInt): ReturnType {.
    closure, ...gcsafe.}
Source Edit
ProtocolError = object of IOError
исключение, которое генерируется, когда сервер не соответствует реализованному протоколу Source Edit
Proxy = ref object
  url*: Uri
  auth*: string
Source Edit
Response = ref object
  version*: string
  status*: string
  headers*: HttpHeaders
  bodyStream*: Stream
Source Edit

Константы

defUserAgent = "Nim-httpclient/2.2.0"
Source Edit

Процедуры

proc `$`(data: MultipartData): string {....raises: [], tags: [], forbids: [].}
преобразовать MultipartData в строку, чтобы она была удобочитаемой при выводе https://github.com/nim-lang/Nim/issues/11863 Исходный код Редактировать
proc `[]=`(p: MultipartData; name, content: string) {.inline,
    ...raises: [ValueError], tags: [], forbids: [].}

Добавить элемент multipart в данные multipart p. Значение добавляется без имени файла и без типа содержимого.

data["username"] = "NimUser"
Исходный код Редактировать
proc `[]=`(p: MultipartData; name: string;
           file: tuple[name, contentType, content: string]) {.inline,
    ...raises: [ValueError], tags: [], forbids: [].}

Добавить файл в данные multipart p, указав имя файла, contentType и содержимое вручную.

data["uploaded_file"] = ("test.html", "text/html",
  "<html><head></head><body><p>test</p></body></html>")
Исходный код Редактировать
proc add(p: MultipartData; name, content: string; filename: string = "";
         contentType: string = ""; useStream = true) {....raises: [ValueError],
    tags: [], forbids: [].}

Добавить значение в данные multipart.

Когда useStream равно false, файл будет прочитан в память.

Вызывается исключение ValueError если name, filename или contentType содержат символы новой строки.

Исходный код Редактировать
proc add(p: MultipartData; xs: MultipartEntries): MultipartData {.discardable,
    ...raises: [ValueError], tags: [], forbids: [].}

Добавить список элементов multipart в данные multipart p. Все значения добавляются без имени файла и без типа содержимого.

data.add({"action": "login", "format": "json"})
Исходный код Редактировать
proc addFiles(p: MultipartData; xs: openArray[tuple[name, file: string]];
              mimeDb = newMimetypes(); useStream = true): MultipartData {.
    discardable, ...raises: [IOError, ValueError], tags: [ReadIOEffect],
    forbids: [].}

Добавить файлы в объект multipart data. Файлы будут передаваться из диска, когда запрос обрабатывается. Когда stream равно false, файлы вместо этого считываются в память, но следует учитывать, что это очень неэффективно с точки зрения памяти даже для небольших файлов. Типы MIME будут определяться автоматически. Вызывается исключение IOError если файл не может быть открыт или считывание завершается ошибкой. Чтобы вручную указать содержимое файла, имя файла и тип MIME, используйте []=.

data.addFiles({"uploaded_file": "public/test.html"})
Исходный код Редактировать
proc body(response: AsyncResponse): Future[string] {....stackTrace: false,
    raises: [Exception, ValueError], tags: [RootEffect], forbids: [].}
Считывает тело ответа и кеширует его. Чтение выполняется только один раз. Исходный код Редактировать
proc body(response: Response): string {....raises: [IOError, OSError],
                                        tags: [ReadIOEffect], forbids: [].}

Получает тело указанного ответа.

Поток тела ответа считывается синхронно.

Исходный код Редактировать
proc close(client: HttpClient | AsyncHttpClient)
Закрывает все соединения, используемые HTTP-клиентом. Исходный код Редактировать
proc code(response: Response | AsyncResponse): HttpCode {.
    ...raises: [ValueError, OverflowDefect].}

Получает указанный HttpCode ответа.

Вызывает исключение ValueError если status ответа не имеет соответствующего HttpCode.

Исходный код Редактировать
proc contentLength(response: Response | AsyncResponse): int

Получает длину содержимого указанного ответа.

Это фактически значение заголовка "Content-Length".

Исключение ValueError будет вызвано, если значение не является целым числом. Если заголовок Content-Length не задан в ответе, ContentLength устанавливается в значение -1.

Исходный код Редактировать
proc contentType(response: Response | AsyncResponse): string {.inline.}

Получает тип содержимого указанного ответа.

Это фактически значение заголовка "Content-Type".

Исходный код Редактировать
proc delete(client: AsyncHttpClient; url: Uri | string): Future[AsyncResponse] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и выполняет запрос DELETE. Эта процедура использует значения httpClient, такие как client.maxRedirects. Исходный код Редактировать
proc delete(client: HttpClient; url: Uri | string): Response
Исходный код Редактировать
proc deleteContent(client: AsyncHttpClient; url: Uri | string): Future[string] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и возвращает содержимое запроса DELETE. Исходный код Редактировать
proc deleteContent(client: HttpClient; url: Uri | string): string
Исходный код Редактировать
proc downloadFile(client: AsyncHttpClient; url: Uri | string; filename: string): Future[
    void]
Исходный код Редактировать
proc downloadFile(client: HttpClient; url: Uri | string; filename: string)
Скачивает url и сохраняет его в filename. Исходный код Редактировать
proc get(client: AsyncHttpClient; url: Uri | string): Future[AsyncResponse] {.
    ...stackTrace: false.}

Подключается к хосту, указанному в URL, и выполняет запрос GET.

Эта процедура использует значения httpClient, такие как client.maxRedirects.

Исходный код Редактировать
proc get(client: HttpClient; url: Uri | string): Response
Исходный код Редактировать
proc getContent(client: AsyncHttpClient; url: Uri | string): Future[string] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и возвращает содержимое запроса GET. Исходный код Редактировать
proc getContent(client: HttpClient; url: Uri | string): string
Исходный код Редактировать
proc getSocket(client: AsyncHttpClient): AsyncSocket {.inline, ...raises: [],
    tags: [], forbids: [].}
Исходный код Редактировать
proc getSocket(client: HttpClient): Socket {.inline, ...raises: [], tags: [],
    forbids: [].}

Получить сетевой сокет, полезно, если вы хотите получить более подробную информацию о соединении.

Этот пример показывает информацию о локальных и удаленных конечных точках:

if client.connected:
  echo client.getSocket.getLocalAddr
  echo client.getSocket.getPeerAddr
Исходный код Редактировать
proc head(client: AsyncHttpClient; url: Uri | string): Future[AsyncResponse] {.
    ...stackTrace: false.}

Подключается к хосту, указанному в URL, и выполняет запрос HEAD.

Эта процедура использует значения httpClient, такие как client.maxRedirects.

Исходный код Изменить
proc head(client: HttpClient; url: Uri | string): Response
Исходный код Изменить
proc lastModified(response: Response | AsyncResponse): DateTime

Получает время последнего изменения указанного ответа.

Эффективно, это значение заголовка «Last-Modified».

Вызывает ValueError если разбор не удался или значение не является правильно отформатированной датой и временем.

Исходный код Изменить
proc newAsyncHttpClient(userAgent = defUserAgent; maxRedirects = 5;
                        sslContext = getDefaultSSL(); proxy: Proxy = nil;
                        headers = newHttpHeaders()): AsyncHttpClient {.
    ...raises: [], tags: [], forbids: [].}

Создаёт новый экземпляр AsyncHttpClient.

userAgent определяет пользовательский агент, который будет использоваться при выполнении запросов.

maxRedirects определяет максимальное количество переадресаций, которые будут следовать, по умолчанию 5.

sslContext определяет контекст SSL для использования в запросах HTTPS.

proxy определяет прокси HTTP для подключений этого HTTP-клиента.

headers определяет HTTP-заголовки.

Пример:

import std/[asyncdispatch, strutils]

proc asyncProc(): Future[string] {.async.} =
  let client = newAsyncHttpClient()
  result = await client.getContent("http://example.com")

let exampleHtml = waitFor asyncProc()
assert "Example Domain" in exampleHtml
assert "Pizza" notin exampleHtml
Исходный код Изменить
proc newHttpClient(userAgent = defUserAgent; maxRedirects = 5;
                   sslContext = getDefaultSSL(); proxy: Proxy = nil;
                   timeout = -1; headers = newHttpHeaders()): HttpClient {.
    ...raises: [], tags: [], forbids: [].}

Создаёт новый экземпляр HttpClient.

userAgent определяет пользовательский агент, который будет использоваться при выполнении запросов.

maxRedirects определяет максимальное количество переадресаций, которые будут следовать, по умолчанию 5.

sslContext определяет контекст SSL для использования в запросах HTTPS. См. Поддержка SSL/TLS

proxy определяет прокси HTTP для подключений этого HTTP-клиента.

timeout определяет количество миллисекунд, разрешенных до возбуждения TimeoutError.

headers определяет HTTP-заголовки.

Пример:

import std/strutils

let exampleHtml = newHttpClient().getContent("http://example.com")
assert "Example Domain" in exampleHtml
assert "Pizza" notin exampleHtml
Исходный код Изменить
proc newMultipartData(): MultipartData {.inline, ...raises: [], tags: [],
    forbids: [].}
Создаёт новый объект MultipartData. Исходный код Изменить
proc newMultipartData(xs: MultipartEntries): MultipartData {.
    ...raises: [ValueError], tags: [], forbids: [].}

Создаёт новый объект multipart data и заполняет его записями xs напрямую.

var data = newMultipartData({"action": "login", "format": "json"})
Исходный код Изменить
proc newProxy(url: string; auth = ""): Proxy {....raises: [], tags: [], forbids: [].}
Создаёт новый объект TProxy. Исходный код Изменить
proc newProxy(url: Uri; auth = ""): Proxy {....raises: [], tags: [], forbids: [].}
Создаёт новый объект TProxy. Исходный код Изменить
proc patch(client: AsyncHttpClient; url: Uri | string; body = "";
           multipart: MultipartData = nil): Future[AsyncResponse] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и выполняет запрос PATCH. Эта процедура использует значения httpClient, такие как client.maxRedirects. Исходный код Изменить
proc patch(client: HttpClient; url: Uri | string; body = "";
           multipart: MultipartData = nil): Response
Исходный код Изменить
proc patchContent(client: AsyncHttpClient; url: Uri | string; body = "";
                  multipart: MultipartData = nil): Future[string] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и возвращает содержимое запроса PATCH. Исходный код Изменить
proc patchContent(client: HttpClient; url: Uri | string; body = "";
                  multipart: MultipartData = nil): string
Исходный код Изменить
proc post(client: AsyncHttpClient; url: Uri | string; body = "";
          multipart: MultipartData = nil): Future[AsyncResponse] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и выполняет запрос POST. Эта процедура использует значения httpClient, такие как client.maxRedirects. Исходный код Изменить
proc post(client: HttpClient; url: Uri | string; body = "";
          multipart: MultipartData = nil): Response
Исходный код Изменить
proc postContent(client: AsyncHttpClient; url: Uri | string; body = "";
                 multipart: MultipartData = nil): Future[string] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и возвращает содержимое запроса POST. Исходный код Изменить
proc postContent(client: HttpClient; url: Uri | string; body = "";
                 multipart: MultipartData = nil): string
Исходный код Изменить
proc put(client: AsyncHttpClient; url: Uri | string; body = "";
         multipart: MultipartData = nil): Future[AsyncResponse] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и выполняет запрос PUT. Эта процедура использует значения httpClient, такие как client.maxRedirects. Исходный код Изменить
proc put(client: HttpClient; url: Uri | string; body = "";
         multipart: MultipartData = nil): Response
Исходный код Изменить
proc putContent(client: AsyncHttpClient; url: Uri | string; body = "";
                multipart: MultipartData = nil): Future[string] {.
    ...stackTrace: false.}
Подключается к хосту, указанному в URL, и возвращает содержимое запроса PUT. Исходный код Изменить
proc putContent(client: HttpClient; url: Uri | string; body = "";
                multipart: MultipartData = nil): string
Исходный код Изменить
proc request(client: AsyncHttpClient; url: Uri | string;
             httpMethod: HttpMethod | string = HttpGet; body = "";
             headers: HttpHeaders = nil; multipart: MultipartData = nil): Future[
    AsyncResponse] {....stackTrace: false.}

Подключается к хосту, указанному в URL, и выполняет запрос с использованием пользовательского метода, заданного строкой httpMethod.

Подключение будет поддерживаться в активном состоянии. Дополнительные запросы на тот же client к тому же хосту не потребуют создания нового подключения. Подключение можно закрыть с помощью процедуры close.

Эта процедура будет следовать переадресациям до максимального числа переадресаций, указанного в client.maxRedirects.

Необходимо убедиться, что url не содержит символов новой строки. В противном случае будет возбуждено AssertionDefect.

headers — это HTTP-заголовки, которые переопределяют client.headers только для этого конкретного запроса и не будут сохранены.

Устарело с версии v1.5: используйте перечисление HttpMethod вместо параметра строки httpMethod, который устарел.

Исходный код Изменить
proc request(client: HttpClient; url: Uri | string;
             httpMethod: HttpMethod | string = HttpGet; body = "";
             headers: HttpHeaders = nil; multipart: MultipartData = nil): Response
Исходный код Изменить

© 2006–2024 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/httpclient.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API