当您使用 CDN 回源到 OSS 遇到跨域问题时,可以尝试先用脚本 AnalysisCors 进行初步排查和定位。
使用方法
[root@izwx4z api]# python AnalysisCore.py -h Usage: AnalysisCore.py [options] 都是必选项 Options: -h, --help show this help message and exit -i AK <Accesskey> 阿里云的云账号或者具备操作 OSS 权限的 RAM 子账号,Accesskey -k SK <AccessKeySecrety> 阿里云的云账号或者具备操作 OSS 权限的 RAM 子账号,Accesskey Secrety -e ED dest oss <endpoint> OSS endpoint,可以从控制台上获取 -b BK dest oss <bucket> OSS bucket -s CDN cors allow <domain> 跨域访问 OSS 的 CDN 域名,必须携带协议头 HTTPS/HTTP -m METH cors http method <GET,POST,PUT,HEADER> cors http method <GET,POST,PUT,HEADER> 指定跨域访问的 HTTP 请求方式,多个请求方法请用 "," 隔开 -t TYPES cors file type multiparts operate or single operate <multi,single> 您可以通过单一文件(single)或者大文件分片(multi)的方式将文件上传、下载到 OSS
CDN 回源到 OSS 遇到跨域问题,通常有以下四种情况:
- 第一种:
python cors.py -i LTA43W -k VTqIcMlVNc -e oss-cn-beijing.aliyuncs.com -b yourBucket -s http://www.zhangyb.com -t multi -m POST
OSS Cors 设置 Access-Control-Allow-Origin Config 没有携带跨域头。
这表明在OSS中执行了分片上传、下载操作,但是没有配置暴露 Headers,<Etag|etag|*>
- 第二种:
python cors.py -i LTA43W -k VTqIcMlVNc -e oss-cn-beijing.aliyuncs.com -b yourBucket -s http://www.zhangyb.com -t multi -m POST,DELETE,HEADE
CDN 回源到 OSS 的跨域请求方式没有在 OSS Cors Access-Control-Allow-Methods 中进行配置。
- 第三种:
python cors.py -i LTA43W -k VTqIcMlVNc -e oss-cn-beijing.aliyuncs.com -b yourBucket -s http://www.zhangyb.com -t multi -m POST,DELETE,HEADE
上传、下载大文件操作时,如果是分片 (multipart) 请求,需要暴露 ETag 头。
- 第四种:
python cors.py -i LTA43W -k VTqIcMlVNc -e oss-cn-beijing.aliyuncs.com -b yourBucket -s http://www.zhangyb.com,http://www.taobao.com -t multi -m POST,DELETE,HEADE
跨域的域名没有在 OSS Cors Access-Control-Allow-Origin 进行配置。
源码
#-*- coding:utf8 -*- #!/usr/bin/env python #Author: hanli #Update: 2018-09-22 from optparse import OptionParser import collections import oss2 import sys import re class MainFunction(): def __init__(self,options): self.args = collections.OrderedDict() self.args["ak"] = options.ak self.args["sk"] = options.sk self.args["ed"] = options.ed self.args["bk"] = options.bk self.args["cdn"] = options.cdn self.args["types"] = options.types self.args["meth"] = options.meth self.left = '\033[1;31;40m' self.right = '\033[0m' # check input parse def CheckParse(self): try: for keys in self.args: if self.args[keys] == None: self.ConsoleLog(0) return False if not (self.args['ed'].startswith("http://") or self.args['ed'].startswith("https://")): self.args['ed'] = "http://"+self.args['ed'] if not (self.args['cdn'].startswith("http://") or self.args['cdn'].startswith("https://")): self.ConsoleLog(1) return False if not re.match("(GET|POST|PUT|HEAD|DELETE|ORIGIN)",self.args['meth']): self.ConsoleLog(7) return False if not re.match("multi|single",self.args['types']): self.ConsoleLog(2) return False except Exception as e: self.ConsoleLog(e) return True # valid cors config def ValidConf(self,origins,methods,headers,expose,flag=True): try: if not (re.match(self.args['cdn'],origins) or origins=="*"): flag=False self.ConsoleLog(3) for meth in self.args['meth'].split(","): if not (meth in methods.split(",") or methods=="*"): flag=False self.ConsoleLog(4,meth) if self.args['types'] == "multi": if not (re.match("(etag|Etag| )",expose)): flag=False self.ConsoleLog(6) if headers == None: flag=False self.ConsoleLog(5) except Exception as e: self.ConsoleLog(e) return flag # get oss cors config def GetCors(self): try: auth = oss2.Auth(self.args['ak'], self.args['sk']) bucket = oss2.Bucket(auth, self.args['ed'], self.args['bk']) cors = bucket.get_bucket_cors() except oss2.exceptions.ServerError as e: self.ConsoleLog(e) except oss2.exceptions.NoSuchCors as e: self.ConsoleLog(e) except oss2.exceptions.NoSuchBucket as e: self.ConsoleLog(e) except oss2.exceptions.AccessDenied as e: self.ConsoleLog(e) else: for rule in cors.rules: if (self.ValidConf(",".join(rule.allowed_origins),",".join(rule.allowed_methods), ",".join(rule.allowed_headers),",".join(rule.expose_headers))): self.ConsoleLog(8) # output error log def ConsoleLog(self,level,meth=None): if level == 0: print('{0}[ERROR]{1}All parameters cannot be empty'.format(self.left,self.right)) if level == 1: print('{0}[ERROR]{1}<-s> CDN domain must be http|https start'.format(self.left,self.right)) if level == 2: print('{0}[ERROR]{1}<-t> Must be multi|single'.format(self.left,self.right)) if level == 3: print('{0}[CheckResult]{1}OSS Access-Control-Allow-Origin Config Error {2}, You can fill in * or http://domain'.format(self.left,self.right,self.args['cdn'])) if level == 4: print('{0}[CheckResult]{1}OSS Access-Control-Allow-Methods Config Error {2}, You can fill in * or methods'.format(self.left,self.right,meth)) if level == 5: print('{0}[CheckResult]{1}Access-Control-Allow-Headers OSS Config Error, You can fill in * or headers'.format(self.left,self.right)) if level == 6: print('{0}[CheckResult]{1}Multipart operate must set expose <etag|Etag|*>'.format(self.left,self.right)) if level == 7: print('{0}[ERROR]{1}<-m> Must be <GET|POST|PUT|HEAD|DELETE|ORIGIN> ,multiple method please "," split'.format(self.left,self.right)) if level == 8: sys.exit("[CheckResult]OSS CORS Config Alright OK") if not isinstance(level,int): print(level) # expr1 = lambda x:x if x.startswith("http://") or x.startswith("https://") else "https://"+x # expr2 = lambda y:y if y.startswith("http://") or y.startswith("https://") else "https://"+y if __name__ == "__main__": parser = OptionParser() parser.add_option("-i",dest="ak",help="<Accesskey>") parser.add_option("-k",dest="sk",help="<AccessKeySecrety>") parser.add_option("-e",dest="ed",help="dest oss <endpoint>") parser.add_option("-b",dest="bk",help="dest oss <bucket>") parser.add_option("-s",dest="cdn",help="cors allow <domain>") parser.add_option("-m",dest="meth",help="cors http method <GET,POST,PUT,HEADER>") parser.add_option("-t",dest="types",help="cors file type multiparts operate or single operate<multi,single>") (options, args) = parser.parse_args() handler = MainFunction(options) if handler.CheckParse(): handler.GetCors()