本文介绍如何使用Python SDK中的sample代码,完成创建主题、创建订阅、启动HttpEndpoint、发布消息、查看HttpEndpoint接收消息和删除主题操作。

步骤一:准备工作

  1. 下载最新版Python SDK,解压后进入mns_python_sdk子目录。
  2. 打开sample.cfg文件,配置AccessKeyId、AccessKeySecret和Endpoint。
    • AccessKeyId、AccessKeySecret
    • Endpoint
      • 访问消息服务MNS的接入地址,登录MNS控制台,单击右上角获取Endpoint查看。
      • 不同地域的接入地址不同。
    • SecurityToken
      • 阿里云访问控制服务提供的短期访问权限凭证,直接使用阿里云账号或者子账号访问不需要配置该项,详细说明,请参见什么是STS
  3. 进入sample目录,后续使用的脚本都在这里。

步骤二:创建主题

运行createtopic.py创建主题。默认创建的主题名称是MySampleTopic,也可以通过参数指定主题名称。详细说明,请参见Topic

  • 运行以下命令:
    python createtopic.py MyTopic1

    返回结果如下:

    Create Topic Succeed! TopicName:MyTopic1 
  • 核心代码:

    endpointaccidacckeytoken从步骤一的配置文件中读取。

    #init my_account, my_topic
    my_account = Account(endpoint, accid, acckey, token)
    topic_name = sys.argv[1] if len(sys.argv) > 1 else "MySampleTopic"
    my_topic = my_account.get_topic(topic_name)
    
    #you can get more information of TopicMeta from mns/topic.py
    topic_meta = TopicMeta()
    try:
        topic_url = my_topic.create(topic_meta)
        print "Create Topic Succeed! TopicName:%s\n" % topic_name
    except MNSExceptionBase, e:
        if e.type == "TopicAlreadyExist":
            print "Topic already exist, please delete it before creating or use it directly."
            sys.exit(0)
        print "Create Topic Fail! Exception:%s\n" % e

步骤三:启动HttpEndpoint

运行simple_http_notify_endpoint.py来启动HttpEndpoint。脚本启动后,输出该脚本的监听地址,这个地址后续作为创建订阅的Endpoint参数,用于接收消息服务MNS推送消息的请求。

  • 服务器功能:
    • 消息服务MNS推送消息请求做签名验证。如果错误,返回MNS 403。
      说明 示例中HttpEndpoint的针对Authorization的校验不能完全规避掉恶意伪造的MNS请求,需要从业务层面上设计从发送端到HttpEndpoint的安全校验机制。
    • 解析推送请求的Body。如果解析正确,打印的日志包含请求的Body;如果解析错误,返回MNS 400。
    • 如果验权和解析Body均正常,返回MNS 201。
  • 运行以下命令:
    python simple_http_notify_endpoint.py 10.101.161.**

    返回结果如下:

    Start Endpoint! Address: http://10.101.161.**:8080 

由于simple_http_notify_endpoint.py的代码较多,请直接查看SDK中的源码。

步骤四:创建订阅

运行subscribe.py创建订阅。第一个参数指定接收消息的HttpEndpoint,使用步骤三中脚本输出的Address;第二个参数指定订阅的主题名称,如果步骤二中指定了主题名称,这里同样指定主题名称;第三个参数指定订阅的名称,默认是MySampleTopic-Sub。详细说明,请参见Subscription

  • 运行以下命令:
    python subscribe.py http://10.101.161.**:8080 MyTopic1 MyTopic1-Sub1

    返回结果如下:

    Create Subscription Succeed! TopicName:MyTopic1 SubName:MyTopic1-Sub1 Endpoint:http://10.101.161.**:8080
  • 核心代码:
    endpointaccidacckeytoken从步骤一的配置文件中读取。
    sub_endpoint = sys.argv[1]
    
    #init my_account, my_topic, my_sub
    my_account = Account(endpoint, accid, acckey, token)
    
    topic_name = sys.argv[2] if len(sys.argv) > 2 else "MySampleTopic"
    my_topic = my_account.get_topic(topic_name)
    
    sub_name = sys.argv[3] if len(sys.argv) > 3 else "MySampleTopic-Sub"
    my_sub = my_topic.get_subscription(sub_name)
    
    #you can get more information of SubscriptionMeta from mns/subscription.py
    sub_meta = SubscriptionMeta(sub_endpoint)
    try:
        topic_url = my_sub.subscribe(sub_meta)
        print "Create Subscription Succeed! TopicName:%s SubName:%s Endpoint:%s\n" % (topic_name, sub_name, sub_endpoint)
    except MNSExceptionBase, e:
        if e.type == "TopicNotExist":
            print "Topic not exist, please create topic."
            sys.exit(0)
        elif e.type == "SubscriptionAlreadyExist":
            print "Subscription already exist, please unsubscribe or use it directly."
            sys.exit(0)
        print "Create Subscription Fail! Exception:%s\n" % e          

步骤五:发布消息

运行publishmessage.py发布多条消息到主题中。如果步骤二中指定了主题名称,这里同样通过第一个参数指定主题名称。详细说明,请参见TopicMessage

  • 运行以下命令:
    python publishmessage.py MyTopic1       

    返回结果如下:

    ==========Publish Message To Topic==========
    TopicName:MyTopic1
    MessageCount:3
    
    Publish Message Succeed. MessageBody:I am test message 0. MessageID:F6EA56633844DBFC-1-154BDFB8059-20000****
    Publish Message Succeed. MessageBody:I am test message 1. MessageID:F6EA56633844DBFC-1-154BDFB805F-20000****
    Publish Message Succeed. MessageBody:I am test message 2. MessageID:F6EA56633844DBFC-1-154BDFB8062-20000****        
  • 核心代码:

    endpointaccidacckeytoken从步骤一的配置文件中读取。

    #init my_account, my_topic
    my_account = Account(endpoint, accid, acckey, token)
    topic_name = sys.argv[1] if len(sys.argv) > 1 else "MySampleTopic"
    my_topic = my_account.get_topic(topic_name)
    
    #publish some messages
    msg_count = 3
    print "%sPublish Message To Topic%s\nTopicName:%s\nMessageCount:%s\n" % (10*"=", 10*"=", topic_name, msg_count)
    
    for i in range(msg_count):
        try:
            msg_body = "I am test message %s." % i
            msg = TopicMessage(msg_body)
            re_msg = my_topic.publish_message(msg)
            print "Publish Message Succeed. MessageBody:%s MessageID:%s" % (msg_body, re_msg.message_id)
        except MNSExceptionBase,e:
            if e.type == "TopicNotExist":
                print "Topic not exist, please create it."
                sys.exit(1)
            print "Publish Message Fail. Exception:%s" % e   

步骤六:查看HttpEndpoint接收消息

在步骤五中,多条消息被发布到了主题中,消息服务MNS会将发布的消息推送给步骤三启动的HttpEndpoint。HttpEndpoint在接收到消息推送请求后,会记录两种日志:access_log和endpoint_log。

  • access_log
    • 启动HttpEndpoint的地方会打印access_log,显示推送消息请求的基本信息,从左往右依次是:RequestTime RequestVersion ReturnCode URI HTTPVersion RequestLength Host Agent MNSRequestID MNSVersion
    • 除打印到屏幕上,access_log会写到日志文件中,文件名格式是access_log.$port,本文对应的日志文件是access_log.8080
    • 运行以下命令查看步骤五发布消息对应的推送请求access_log:
      python simple_http_notify_endpoint.py

      返回结果如下:

      Start Endpoint! Address: http://10.101.161.**:8080
      [17/May/2016 17:10:56]"POST" "201" "/notifications" "HTTP/1.1" "495" "10.101.161.**:8080" "Aliyun Notification Service Agent" "573AE020B2B71CFC6801A6EF" "2015-06-06"
      [17/May/2016 17:10:56]"POST" "201" "/notifications" "HTTP/1.1" "495" "10.101.161.**:8080" "Aliyun Notification Service Agent" "573AE020B2B71CFC6801A712" "2015-06-06"
      [17/May/2016 17:10:56]"POST" "201" "/notifications" "HTTP/1.1" "495" "10.101.161.**:8080" "Aliyun Notification Service Agent" "573AE020B2B71CFC6801A704" "2015-06-06"
  • endpoint_log
    • 记录每个请求的详细信息,包含完整的Header、Body以及解析后消息各属性的信息。
    • 日志的文件名格式是endpoint_log.$port,本文对应的日志文件是endpoint_log.8080
    • 运行以下命令查看步骤五发布消息对应的推送请求的endpoint_log:
      cat endpoint_log.8080      

      返回结果如下:

      ...
      [2016-05-17 17:10:56] [root] [INFO] [simple_http_notify_endpoint.py:47] [1096657216] Notify Message Succeed!
      MessageMD5                    : 075C3D4AEB2D2F2D6A4C17C9D6DBBEBB
      TopicOwner                    : 126912835662****
      PublishTime                   : 1463476256857
      Subscriber                    : 126912835662****
      MessageTag                    :
      SubscriptionName              : MyTopic1-Sub1
      MessageId                     : F6EA56633844DBFC-1-154BDFB8059-20000****
      Message                       : I am test message 0.
      TopicName                     : MyTopic1
      [2016-05-17 17:10:56] [root] [INFO] [simple_http_notify_endpoint.py:47] [1123260736] Notify Message Succeed!
      MessageMD5                    : 3BCFB142A3CC597F5D409BFE9DB1B885
      TopicOwner                    : 126912835662****
      PublishTime                   : 1463476256866
      Subscriber                    : 126912835662****
      MessageTag                    :
      SubscriptionName              : MyTopic1-Sub1
      MessageId                     : F6EA56633844DBFC-1-154BDFB8062-20000****
      Message                       : I am test message 2.
      TopicName                     : MyTopic1
      [2016-05-17 17:10:56] [root] [INFO] [simple_http_notify_endpoint.py:47] [1112770880] Notify Message Succeed!
      MessageMD5                    : 8356BC7FFBD22CC971BE7FF7427202B6
      TopicOwner                    : 126912835662****
      PublishTime                   : 1463476256863
      Subscriber                    : 126912835662****
      MessageTag                    :
      SubscriptionName              : MyTopic1-Sub1
      MessageId                     : F6EA56633844DBFC-1-154BDFB805F-20000****
      Message                       : I am test message 1.
      TopicName                     : MyTopic1        

步骤七:删除主题

运行deletetopic.py删除主题。如果步骤二中指定了主题名称,这里同样通过第一个参数指定主题名称。

  • 运行以下命令:
    python deletetopic.py MyTopic1       

    返回结果如下:

    Delete Topic Succeed! TopicName:MyTopic1        
  • 核心代码:
    #init my_account, my_topic
    my_account = Account(endpoint, accid, acckey, token)
    topic_name = sys.argv[1] if len(sys.argv) > 1 else "MySampleTopic"
    my_topic = my_account.get_topic(topic_name)
    
    try:
        my_topic.delete()
        print "Delete Topic Succeed! TopicName:%s\n" % topic_name
    except MNSExceptionBase, e:
        print "Delete Topic Fail! Exception:%s\n" % e