我应该如何配置标头以向 APNs 进行 HTTP/2 POST 以避免“收到重复的伪标头字段”错误?

Jak*_*ake 7 python ios http2

我对 HTTP 内容还很陌生,主要使用 iOS,所以请耐心等待。我正在使用 httpx python 库尝试向 iPhone 发送通知,因为我必须进行 HTTP/2 POST 才能执行此操作。苹果的文档说它需要“:method”和“:path”标头,但是当我尝试使用这些标头进行 POST 时,

headers = { 
    ':method' : 'POST', 
    ':path' : '/3/device/{}'.format(deviceToken),  
    ...
    }
Run Code Online (Sandbox Code Playgroud)

我收到错误

h2.exceptions.ProtocolError:收到重复的伪标头字段 b':路径

很明显包含“:path”标头存在问题,但我也需要发送它,所以我不确定我做错了什么。苹果的文档还说

将 :path 和授权值编码为文字标头字段,无需索引。

将所有其他字段编码为具有增量索引的文字标头字段。

我真的不知道这意味着什么,或者如何实现它,或者它是否相关。我认为 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'
Run Code Online (Sandbox Code Playgroud)

要求:

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()
Run Code Online (Sandbox Code Playgroud)

Moh*_*one 4

只需要附加'/3/device/{}'.format(deviceToken)到 devServer url 作为路径,“:path”伪标头就会自动设置为它。

那是,

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

解释:

“:path”、“:method”和“:scheme”伪标头通常不需要在 http2 中手动添加

参考:超文本传输​​协议版本 2 (HTTP/2)