基于Python的阿里云API签名算法及邮件推送服务

来源:互联网 发布:锐捷 mac过滤 编辑:程序博客网 时间:2024/05/18 17:59

  因为TalkingCoder的服务都是部署在阿里云ECS上的,而之前一直用SMTP来发邮件遇到种种问题,正好最近阿里云在推邮件推送服务,就尝试把它迁移过去。阿里云的推送速度、数量和监控会更好一点。邮件推送服务其实就是一个简单的API调用,但在和Celery集成过程中,却遇到几个很头疼的小问题。下面一一说明我遇到的一些坑。

  签名算法

  阿里云有提供SDK,但是签名算法目前只有JAVA、PHP、C#支持,其他需要自己写。在查了一些资料后,基于这篇文章,最终实现了邮件推送。

  先看一下这个核心类:

  # coding=utf-8

  import base64

  import hmac

  from hashlib import sha1

  import urllib

  import time

  import uuid

  from config.base import ALIYUN_ACCESS_KEY_ID, ALIYUN_ACCESS_KEY_SECRET

  class AliyunMonitor:

  def __init__(self, url):

  self.access_id = ALIYUN_ACCESS_KEY_ID

  self.access_secret = ALIYUN_ACCESS_KEY_SECRET

  self.url = url

  # 签名

  def sign(self, accessKeySecret, parameters):

  sortedParameters = sorted(parameters.items(), key=lambda parameters: parameters[0])

  canonicalizedQueryString = ''

  for (k, v) in sortedParameters:

  canonicalizedQueryString += '&' + self.percent_encode(k) + '=' + self.percent_encode(v)

  stringToSign = 'GET&%2F&' + self.percent_encode(canonicalizedQueryString[1:]) # 使用get请求方法

  h = hmac.new(accessKeySecret + "&", stringToSign, sha1)

  signature = base64.encodestring(h.digest()).strip()

  return signature

  def percent_encode(self, encodeStr):

  encodeStr = str(encodeStr)

  # 下面这行挺坑的,使用上面文章中的方法会在某些情况下报错,后面详细说明

  res = urllib.quote(encodeStr.decode('utf-8').encode('utf-8'), '')

  res = res.replace('+', '%20')

  res = res.replace('*', '%2A')

  res = res.replace('%7E', '~')

  return res

  def make_url(self, params):

  timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())

  parameters = {

  'Format': 'JSON',

  'Version': '2015-11-23',

  'AccessKeyId': self.access_id,

  'SignatureVersion': '1.0',

  'SignatureMethod': 'HMAC-SHA1',

  'SignatureNonce': str(uuid.uuid1()),

  'Timestamp': timestamp,

  }

  for key in params.keys():

  parameters[key] = params[key]

  signature = self.sign(self.access_secret, parameters)

  parameters['Signature'] = signature

  # return parameters成都男性阴茎短小的原因有哪些?

  url = self.url + "/?" + urllib.urlencode(parameters)

  return url

  然后,我们写一个send_email的方法来调用:

  # coding=utf-8

  import requests

  from lib.aliyun_monitor import AliyunMonitor

  def send_email(email_address, subject, text):

  payload = {

  'Action': 'SingleSendMail',

  'AccountName': 'mail@mail.xxx.com',

  'ReplyToAddress': 'true',

  'AddressType': 0,

  'ToAddress': email_address,

  'FromAlias': 'TalkingCoder',

  'Subject': subject,

  'HtmlBody': text

  }男性射出的精子是黄色的怎么办?

  aliyun = AliyunMonitor("http://dm.aliyuncs.com")

  url = aliyun.make_url(payload)

  request = requests.get(url)

  print request.text

  send_email('test@test.com', '标题', '内容')

  这里使用了requests来get请求。

  注意

  代码写到这里,在本机环境测试都OK的,然后就往Celery上集成。这里要说明一下,因为之前是用SMTP来发邮件,平均发一封2秒左右吧,这样同步发的话是一件很恐怖的事情,所以就丢给Celery异步去执行任务了。现在集成了阿里的云邮件服务后,其实是可以同步发了,因为本身一个API请求也很快,但Celery闲着也是闲着,为什么不用起来呢,所以后面问题就来了。

  就是第一段签名代码里写道的,原文中使用的是res = urllib.quote(encodeStr.decode(sys.stdin.encoding).encode('utf8'), ''),这样普通执行任务可以,但是nohup后和使用Celery都会报一个错误,大致意思是decode的第一个参数必须是String,因为当时nohup后就比较难看到Celery的日志,最后在本机模拟相同环境才知道原因,改为了res = urllib.quote(encodeStr.decode('utf-8').encode('utf-8'), '') 之后才可以。

  最后,通过环境变量,在开发环境不使用Celery,在生成环境再使用

原创粉丝点击