簡體   English   中英

Azure 通知中心延遲問題

[英]Azure Notification Hub Delay Issue

我正在使用 Azure 通知中心將推送通知從 Raspberry pi 發送到 android 應用程序。

我正在根據這篇文章使用 REST API 使用 python 客戶端應用程序如何使用 Python 中的通知中心

一切正常,但從 Raspberry pi 到 Android 應用程序的每個通知都有近 2 秒的延遲! 如何避免這種延遲並在同一秒內在 Android 設備上獲得通知。

我的python腳本

import time
import hmac
import base64
import hashlib
import json
import urllib.parse
import http.client


class Notification:
    def __init__(self, notification_format=None, payload=None, debug=0):
        valid_formats = ['template', 'apple', 'gcm', 'windows', 'windowsphone', "adm", "baidu"]
        if not any(x in notification_format for x in valid_formats):
            raise Exception(
                "Invalid Notification format. " +
                "Must be one of the following - 'template', 'apple', 'gcm', 'windows', 'windowsphone', 'adm', 'baidu'")

        self.format = notification_format
        self.payload = payload

        # array with keynames for headers
        # Note: Some headers are mandatory: Windows: X-WNS-Type, WindowsPhone: X-NotificationType
        # Note: For Apple you can set Expiry with header: ServiceBusNotification-ApnsExpiry
        # in W3C DTF, YYYY-MM-DDThh:mmTZD (for example, 1997-07-16T19:20+01:00).
        self.headers = None


class NotificationHub:
    API_VERSION = "?api-version=2013-10"
    DEBUG_SEND = "&test"

    def __init__(self, connection_string=None, hub_name=None, debug=0):
        self.HubName = hub_name
        self.Debug = debug

        # Parse connection string
        parts = connection_string.split(';')
        if len(parts) != 3:
            raise Exception("Invalid ConnectionString.")

        for part in parts:
            if part.startswith('Endpoint'):
                self.Endpoint = 'https' + part[11:]
            if part.startswith('SharedAccessKeyName'):
                self.SasKeyName = part[20:]
            if part.startswith('SharedAccessKey'):
                self.SasKeyValue = part[16:]

    @staticmethod
    def get_expiry():
        # By default returns an expiration of 5 minutes (=300 seconds) from now
        return int(round(time.time() + 300))

    @staticmethod
    def encode_base64(data):
        return base64.b64encode(data)

    def sign_string(self, to_sign):
        key = self.SasKeyValue.encode('utf-8')
        to_sign = to_sign.encode('utf-8')
        signed_hmac_sha256 = hmac.HMAC(key, to_sign, hashlib.sha256)
        digest = signed_hmac_sha256.digest()
        encoded_digest = self.encode_base64(digest)
        return encoded_digest

    def generate_sas_token(self):
        target_uri = self.Endpoint + self.HubName
        my_uri = urllib.parse.quote(target_uri, '').lower()
        expiry = str(self.get_expiry())
        to_sign = my_uri + '\n' + expiry
        signature = urllib.parse.quote(self.sign_string(to_sign))
        auth_format = 'SharedAccessSignature sig={0}&se={1}&skn={2}&sr={3}'
        sas_token = auth_format.format(signature, expiry, self.SasKeyName, my_uri)
        return sas_token

    def make_http_request(self, url, payload, headers):
        parsed_url = urllib.parse.urlparse(url)
        connection = http.client.HTTPSConnection(parsed_url.hostname, parsed_url.port)

        if self.Debug > 0:
            connection.set_debuglevel(self.Debug)
            # adding this querystring parameter gets detailed information about the PNS send notification outcome
            url += self.DEBUG_SEND
            print("--- REQUEST ---")
            print("URI: " + url)
            print("Headers: " + json.dumps(headers, sort_keys=True, indent=4, separators=(' ', ': ')))
            print("--- END REQUEST ---\n")

        connection.request('POST', url, payload, headers)
        response = connection.getresponse()

        if self.Debug > 0:
            # print out detailed response information for debugging purpose
            print("\n\n--- RESPONSE ---")
            print(str(response.status) + " " + response.reason)
            print(response.msg)
            print(response.read())
            print("--- END RESPONSE ---")

        elif response.status != 201:
            # Successful outcome of send message is HTTP 201 - Created
            raise Exception(
                "Error sending notification. Received HTTP code " + str(response.status) + " " + response.reason)

        connection.close()

    def send_notification(self, notification, tag_or_tag_expression=None):
        url = self.Endpoint + self.HubName + '/messages' + self.API_VERSION

        json_platforms = ['template', 'apple', 'gcm', 'adm', 'baidu']

        if any(x in notification.format for x in json_platforms):
            content_type = "application/json"
            payload_to_send = json.dumps(notification.payload)
        else:
            content_type = "application/xml"
            payload_to_send = notification.payload

        headers = {
            'Content-type': content_type,
            'Authorization': self.generate_sas_token(),
            'ServiceBusNotification-Format': notification.format
        }

        if isinstance(tag_or_tag_expression, set):
            tag_list = ' || '.join(tag_or_tag_expression)
        else:
            tag_list = tag_or_tag_expression

        # add the tags/tag expressions to the headers collection
        if tag_list != "":
            headers.update({'ServiceBusNotification-Tags': tag_list})

        # add any custom headers to the headers collection that the user may have added
        if notification.headers is not None:
            headers.update(notification.headers)

        self.make_http_request(url, payload_to_send, headers)

    def send_apple_notification(self, payload, tags=""):
        nh = Notification("apple", payload)
        self.send_notification(nh, tags)

    def send_gcm_notification(self, payload, tags=""):
        nh = Notification("gcm", payload)
        self.send_notification(nh, tags)

    def send_adm_notification(self, payload, tags=""):
        nh = Notification("adm", payload)
        self.send_notification(nh, tags)

    def send_baidu_notification(self, payload, tags=""):
        nh = Notification("baidu", payload)
        self.send_notification(nh, tags)

    def send_mpns_notification(self, payload, tags=""):
        nh = Notification("windowsphone", payload)

        if "<wp:Toast>" in payload:
            nh.headers = {'X-WindowsPhone-Target': 'toast', 'X-NotificationClass': '2'}
        elif "<wp:Tile>" in payload:
            nh.headers = {'X-WindowsPhone-Target': 'tile', 'X-NotificationClass': '1'}

        self.send_notification(nh, tags)

    def send_windows_notification(self, payload, tags=""):
        nh = Notification("windows", payload)

        if "<toast>" in payload:
            nh.headers = {'X-WNS-Type': 'wns/toast'}
        elif "<tile>" in payload:
            nh.headers = {'X-WNS-Type': 'wns/tile'}
        elif "<badge>" in payload:
            nh.headers = {'X-WNS-Type': 'wns/badge'}

        self.send_notification(nh, tags)

    def send_template_notification(self, properties, tags=""):
        nh = Notification("template", properties)
        self.send_notification(nh, tags)



isDebug = True
myConnectionString =  "connection string"
hub = NotificationHub(myConnectionString, "cavenotificationhub", isDebug)
data = {}
data['response'] = 'data: R1|X1|S1,1|$'
json_data = json.dumps(data,separators=(',',':'))
print(json_data)
#gcm_payload = {"response":R1|X1|S1,1}
val= "R1|X1|S1,1|$"
gcm_payload = { 'data' : {'response': ''+val+''}}
hub.send_gcm_notification(gcm_payload)

附上日志:

Windows 10 Surface Pro 3 - Python 3.4 script

**** Send GCM Notitification START>  2016-05-08 10:42:07.883226
*** make_http_request connection OPEN>  2016-05-08 10:42:08.139328

--- REQUEST ---
#Request header
--- END REQUEST ---

*** make_http_request START>  2016-05-08 10:42:08.165356
#Sending request to Azure
*** make_http_request END>  2016-05-08 10:42:09.016024

--- RESPONSE ---
#Response received from Azure
--- END RESPONSE ---

*** make_http_request connection CLOSE>  2016-05-08 10:42:09.184785
**** Send GCM Notitification END>  2016-05-08 10:42:09.188788

################################################################################################################################ Raspberry Pi Model B+ V1.2 - Python 2.7 script

('*** Send GCM Notitification START> ', '2016-05-08 10:46:32.692844') ('*** make_http_request connection OPEN> ', '2016-05-08 10:46:32.698456')

--- REQUEST ---
#Request header
--- END REQUEST ---

('*** make_http_request START> ', '2016-05-08 10:46:32.705946')
#Sending request to Azure ('*** make_http_request END> ', '2016-05-08 10:46:39.557759')

--- RESPONSE ---
#Response received from Azure
--- END RESPONSE ---

('*** make_http_request connection CLOSE> ', '2016-05-08 10:46:39.569713') ('*** Send GCM Notitification END> ', '2016-05-08 10:46:39.570986')

################################################################################################################################ Raspberry Pi 2 Model B V1.1 - Python 2.7 script

('*** Send GCM Notitification START> ', '2016-05-08 05:36:49.721024') ('*** make_http_request connection OPEN> ', '2016-05-08 05:36:49.732056')

--- REQUEST ---
#Request header
--- END REQUEST ---

('*** make_http_request START> ', '2016-05-08 05:36:49.733069')
#Sending request to Azure ('*** make_http_request END> ', '2016-05-08 05:36:50.741605')

--- RESPONSE ---
#Response received from Azure
--- END RESPONSE ---

('*** make_http_request connection CLOSE> ', '2016-05-08 05:36:50.746248') ('*** Send GCM Notitification END> ', '2016-05-08 05:36:50.747000')

那太難了! 首先,我們需要了解導致該問題的原因是什么。

1) 從 Raspberry Pi 2 到后端的請求可能很長。 要了解這是否是問題所在,請使用Service Bus Explorer ,連接到您的 SB 命名空間,然后打開通知中心,選擇 Android 窗格並嘗試從該窗格發送推送(參見屏幕截圖)。 如果您將更快地收到通知,那么 RPI 就以某種方式參與其中。

2)如果您發現延遲沒有區別,並且使用 RPI 或 SB 發送通知導致 2-3 秒后推送,那么我會說這絕對沒問題。 例如, 請參閱該主題 這真的取決於很多因素,當我們試圖減少時間(我們有時觀察到 5-10 秒)時,我們發現經常出現的問題不是客戶端或代理(在這種情況下是 NH),而是通知平台。

而且,當然,您不應該期望在同一秒內發送通知。 我們擁有的最好的 - 下一個或 2 秒后。 但是真的不能保證。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM