本文共 4797 字,大约阅读时间需要 15 分钟。
出现 signature 一般出现客户端自签名调 API 的操作中, signature 的计算稍微复杂点,建议最好用 SDK 来替代计算的过程和多样性。如果业务强需求,先要读懂如果计算 signature。
Header | URL |
---|---|
不支持设置 expires | 支持设置 expires |
常用 method GET、POST、PUT | 常用 method GET、PUT |
date 时间是 GMT 格式 | date 替换成 expires 变成时间戳 |
signature 不需要 URL encode | signature 需要 URL encode |
当客户通过 header 或者 URL 中自签名计算 signature 时,经常会遇到计算签名失败 “The request signature we calculated does not match the signature you provided” ,可以参考以下 demo 演示了如何调用 API 自签名时上传 Object 到 OSS,注意签名和 header 加入的内容。
#! /us/bin/envy python#Author: hanli#Update: 2018-09-29from optparse import OptionParserimport urllib, urllib2import datetimeimport base64import hmacimport shaimport osimport sysimport timeclass Main(): # Initial input parse def __init__(self,options): self.ak = options.ak self.sk = options.sk self.ed = options.ed self.bk = options.bk self.fi = options.fi self.oj = options.objects self.left = '\033[1;31;40m' self.right = '\033[0m' self.types = "application/x-www-form-urlencoded" self.url = 'http://{0}.{1}/{2}'.format(self.bk,self.ed,self.oj) # Check client input parse def CheckParse(self): if (self.ak and self.sk and self.ed and self.bk and self.oj and self.fi) != None: if str(self.ak and self.sk and self.ed and self.bk and self.oj and self.fi): self.PutObject() else: self.ConsoleLog("error","Input parameters cannot be empty") # GET local GMT time def GetGMT(self): SRM = datetime.datetime.utcnow() GMT = SRM.strftime('%a, %d %b %Y %H:%M:%S GMT') return GMT # GET Signature def GetSignature(self): mac = hmac.new("{0}".format(self.sk),"PUT\n\n{0}\n{1}\n/{2}/{3}".format(self.types,self.GetGMT(),self.bk,self.oj), sha) Signature = base64.b64encode(mac.digest()) return Signature # PutObject def PutObject(self): try: with open(self.fi) as fd: files = fd.read() except Exception as e: self.ConsoleLog("error",e) try: request = urllib2.Request(self.url, files) request.add_header('Host','{0}.{1}'.format(self.bk,self.ed)) request.add_header('Date','{0}'.format(self.GetGMT())) request.add_header('Authorization','OSS {0}:{1}'.format(self.ak,self.GetSignature())) request.get_method = lambda:'PUT' response = urllib2.urlopen(request,timeout=10) fd.close() self.ConsoleLog(response.code,response.headers) except Exception,e: self.ConsoleLog("error",e) # output error log def ConsoleLog(self,level=None,mess=None): if level == "error": sys.exit('{0}[ERROR:]{1}{2}'.format(self.left,self.right,mess)) else: sys.exit('\nHTTP/1.1 {0} OK\n{1}'.format(level,mess))if __name__ == "__main__": parser = OptionParser() parser.add_option("-i",dest="ak",help="Must fill in Accesskey") parser.add_option("-k",dest="sk",help="Must fill in AccessKeySecrety") parser.add_option("-e",dest="ed",help="Must fill in endpoint") parser.add_option("-b",dest="bk",help="Must fill in bucket") parser.add_option("-o",dest="objects",help="File name uploaded to oss") parser.add_option("-f",dest="fi",help="Must fill localfile path") (options, args) = parser.parse_args() handler = Main(options) handler.CheckParse()
PUT /yuntest HTTP/1.1Accept-Encoding: identityContent-Length: 147Connection: closeUser-Agent: Python-urllib/2.7Date: Sat, 22 Sep 2018 04:36:52 GMTHost: yourBucket.oss-cn-shanghai.aliyuncs.comContent-Type: application/x-www-form-urlencodedAuthorization: OSS B0g3mdt:lNCA4L0P43Ax
HTTP/1.1 200 OKServer: AliyunOSSDate: Sat, 22 Sep 2018 04:36:52 GMTContent-Length: 0Connection: closex-oss-request-id: 5BA5C6E4059A3C2FETag: "D0CAA153941AAA1CBDA38AF"x-oss-hash-crc64ecma: 8478734191999037841Content-MD5: 0MqhU5QbIp3Ujqqhy9o4rw==x-oss-server-time: 15
分析:
遇到类似问题,抓包是最能快速看到问题的。同时也必须要了解下 OSS 请求 header 中携带了 Content-tpye ,那么 signature 计算就要加上 Content-tpye ,保持一致。
分析:
出现这个问题不区分什么 SDK 都会出现,问题原因是由于客户端发起的 HEAD 请求在通过 CDN 回原到 OSS 时,CDN 回原是用的 GET 请求,而 OSS 收到时就用 GET 请求方式去计算签名,得到的结果肯定和客户端计算不一致,可以升级到阿里云 CDN 处理。以上分析只适合上述场景。
问题可以通过 tcpdump 抓包或者 Wireshark 对比一下即可知道。
转载地址:http://eecta.baihongyu.com/