Как я должен настроить свои заголовки для отправки сообщения HTTP / 2 в APNs, чтобы избежать ошибки «Получено дублированное поле псевдоголовника»?

#python #ios #http2

#python #iOS #http2

Вопрос:

Я довольно новичок в HTTP-материалах, в первую очередь придерживаюсь iOS, поэтому, пожалуйста, потерпите меня. Я использую библиотеку python httpx, чтобы попытаться отправить уведомление на iPhone, потому что для этого мне нужно создать сообщение HTTP / 2. В документации Apple говорится, что для этого требуются заголовки «: метод» и «: путь», но я, когда пытаюсь создать сообщение с включенными этими заголовками,

 headers = { 
    ':method' : 'POST', 
    ':path' : '/3/device/{}'.format(deviceToken),  
    ...
    }
 

Я получаю сообщение об ошибке

h2.исключения.Ошибка протокола: получено дублированное поле псевдоголовника b’:path

Довольно очевидно, что существует проблема с включением заголовка «:path», но мне также необходимо отправить его, поэтому я не уверен, что я делаю неправильно. В документации Apple также говорится:

Кодируйте значения:path и authorization как поля буквального заголовка без индексации.

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

Я действительно не знаю, что это значит или как это реализовать, или если это связано. Я бы подумал, что httpx объединит мой заголовок «:path» с заголовком по умолчанию, чтобы устранить дубликат, но я просто плюю здесь.

Полная трассировка

 File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpx/_client.py", line 992, in post
    return self.request(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpx/_client.py", line 733, in request
    return self.send(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpx/_client.py", line 767, in send
    response = self._send_handling_auth(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpx/_client.py", line 805, in _send_handling_auth
    response = self._send_handling_redirects(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpx/_client.py", line 837, in _send_handling_redirects
    response = self._send_single_request(request, timeout)
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpx/_client.py", line 861, in _send_single_request
    (status_code, headers, stream, ext) = transport.request(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py", line 218, in request
    response = connection.request(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 106, in request
    return self.connection.request(method, url, headers, stream, ext)
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpcore/_sync/http2.py", line 119, in request
    return h2_stream.request(method, url, headers, stream, ext)
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpcore/_sync/http2.py", line 292, in request
    self.send_headers(method, url, headers, has_body, timeout)
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpcore/_sync/http2.py", line 330, in send_headers
    self.connection.send_headers(self.stream_id, headers, end_stream, timeout)
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/httpcore/_sync/http2.py", line 227, in send_headers
    self.h2_state.send_headers(stream_id, headers, end_stream=end_stream)
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/h2/connection.py", line 770, in send_headers
    frames = stream.send_headers(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/h2/stream.py", line 865, in send_headers
    frames = self._build_headers_frames(
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/h2/stream.py", line 1252, in _build_headers_frames
    encoded_headers = encoder.encode(headers)
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/hpack/hpack.py", line 249, in encode
    for header in headers:
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/h2/utilities.py", line 496, in inner
    for header in headers:
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/h2/utilities.py", line 441, in _validate_host_authority_header
    for header in headers:
  File "/Users/User/.pyenv/versions/3.9.0/lib/python3.9/site-packages/h2/utilities.py", line 338, in _reject_pseudo_header_fields
    raise ProtocolError(
h2.exceptions.ProtocolError: Received duplicate pseudo-header field b':method'
 

Запрос:

 devServer = "https://api.sandbox.push.apple.com:443"
title = "some title"
notification = { "aps": { "alert": title, "sound": "someSound.caf" } }
client = httpx.Client(http2=True)
try:
    r = client.post(devServer, json=notification, headers=headers)
finally:
    client.close()
 

Комментарии:

1. Как выглядит ваш вызов http-запроса?

2. @ C.Nivs добавил это к моему вопросу.

3. Извлеките «:path» и «:method» из ваших заголовков — httpx, через http2, помещает их автоматически. (Я использую более или менее тот же код, за вычетом этих заголовков!)

4. @Sebastian Итак, как мне передать токен устройства без заголовка «:path»? Я подумал, что могу обойтись без «:method», поскольку POST может быть выведен, но я просто не уверен, как иначе передать информацию о токене устройства…

5. @Jake введите путь в URL, который вы передаете функции post. Прямо сейчас вы просто вводите devServer , вместо этого сделайте что-то вроде этого: '{}/3/device/{}'.format(devServer, deviceToken)

Ответ №1:

Просто нужно добавить '/3/device/{}'.format(deviceToken) к URL-адресу devServer в качестве пути, и псевдоголовок «:path» будет автоматически установлен на него.

то есть,

 devServer = 'https://api.sandbox.push.apple.com:443/3/device/{}'.format(deviceToken) 
 

Объяснение:

Псевдоголовки «: path», «:method» и «: scheme» обычно не нужно добавлять вручную в http2

Ссылка: протокол передачи гипертекста версии 2 (HTTP / 2)