我应该如何配置我的标头以对 APNs 进行 HTTP/2 POST 以避免“收到重复的伪标头字段”错误?
Posted
技术标签:
【中文标题】我应该如何配置我的标头以对 APNs 进行 HTTP/2 POST 以避免“收到重复的伪标头字段”错误?【英文标题】:How should I configure my headers to make an HTTP/2 POST to APNs to avoid "Received duplicate pseudo-header field" error? 【发布时间】:2021-03-26 13:56:46 【问题描述】:我对 HTTP 的东西还很陌生,主要是使用 ios,所以请多多包涵。 我正在使用 httpx python 库尝试向 iPhone 发送通知,因为我必须进行 HTTP/2 POST 才能这样做。 Apple 的文档说它需要 ":method" 和 ":path" 标头,但是当我尝试使用包含这些标头的 POST 时,
headers =
':method' : 'POST',
':path' : '/3/device/'.format(deviceToken),
...
我得到了错误
h2.exceptions.ProtocolError: 收到重复的伪头字段 b':path
很明显,包含“: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'
请求:
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()
【问题讨论】:
你的 http 请求调用是什么样的? @C.Nivs 将其添加到我的问题中。 把“:path”和“:method”从你的头文件中取出——httpx,通过http2,自动把它们放进去。 (我使用或多或少相同的代码,减去那些标题!) @Sebastian 那么如何在没有“:path”标头的情况下传入设备令牌?我想我可以不用“:方法”,因为可以推断出 POST,但我只是不确定如何传递设备令牌信息...... @Jake 将路径放入您传递给 post 函数的 URL 中。现在,您只需输入devServer
,而是将其设置为:'/3/device/'.format(devServer, deviceToken)
【参考方案1】:
只需将'/3/device/'.format(deviceToken)
附加到devServer url作为路径,“:path”伪标头就会自动设置到它。
也就是说,
devServer = 'https://api.sandbox.push.apple.com:443/3/device/'.format(deviceToken)
解释:
“:path”、“:method”和“:scheme”pseudo-headers一般不需要在http2中手动添加
参考:Hypertext Transfer Protocol Version 2 (HTTP/2)
【讨论】:
以上是关于我应该如何配置我的标头以对 APNs 进行 HTTP/2 POST 以避免“收到重复的伪标头字段”错误?的主要内容,如果未能解决你的问题,请参考以下文章
我应该对 API 密钥使用 Authorization 标头吗
如何使用标准 C#.NET 发送带有“apns-expiration”标头的推送通知?
OpenSSL 标头版本!= 影响 APNS 的 HTTP/2 的 OpenSSL 库版本