(资料图片仅供参考)
背景
运维同学通过网关平台下发nginx配置文件,下发的过程是先灰度发布,发灰度机器,然后需要验证域名的请求是否正常,然后在下发其他生产机器,但是验证过程是人为操作,这就不可避免的会有些同学不进行验证,点击“继续”发布,如果出现问题将是灾难性的(别问为什么是灾难性的)。为了避免这个问题的出现,发布平台添加自动校验的过程,也就是在灰度机器发完,点击继续时,网关平台会将重点域名进行准确性校验,但是只验证连通性和证书,不会进行具体数据的验证。
过程
一般人工校验都是本地配置DNS解析(/etc/hosts),在通过域名请求,使域名打到目标机器上。如果是机器自动校验还是要配置DNS解析就难免有些不够便利所以还是想通过参数传入目标IP的形式,使重点域名可以达到目标机器上
代码
按照以下代码可以实现流量打到目标机器
response = requests.request("GET", "https://10.12.13.14/healthcheck", headers={"Host":"www.nginxtest.com"}, data={}, verify = False)
但是如果是https,必须得指定verify=false,禁用证书校验。但是却违背了我们的意愿因为在requests校验证书不会从headers里取,只会从url中取,所以会报无法匹配10.12.13.14的证书
有两种方式去解决本环境是Python2的环境,与Python3稍微有些差别,已经标出。
方法1
使用requests的底层 urllib3
import urllib3pool = urllib3.HTTPSConnectionPool("123.456.23.123",assert_hostname="nginxtest.com")# pool = urllib3.HTTPSConnectionPool("123.456.23.123",assert_hostname="nginxtest.com", server_hostname="nginxtest.com" ) # 注释掉的是Python3的写法,Python2 如果这么写会报 TypeError: __init__() got an unexpected keyword argument "server_hostname"ss = pool.urlopen("GET","/healthcheck",headers={"Host": "nginxtest.com"},assert_same_host=False)print(ss.status)
方法2
用urllib3 封装 HTTPAdapter
# 封装函数 resolved_ip是目标IPimport requestsclass HostHeaderSSLAdapter(requests.adapters.HTTPAdapter): def __init__(self, resolved_ip): super(HostHeaderSSLAdapter,self).__init__() #python2 #super().__init__() #python3 self.resolved_ip = resolved_ip def send(self, request, **kwargs): from urlparse import urlparse #python2 #from urllib.parse import urlparse #python3 connection_pool_kwargs = self.poolmanager.connection_pool_kw result = urlparse(request.url) if result.scheme == "https" and self.resolved_ip: request.url = request.url.replace( "https://" + result.hostname, "https://" + self.resolved_ip, ) #connection_pool_kwargs["server_hostname"] = result.hostname # SNI python2 需要屏蔽掉 不然会报 非预期的字段 key_server_hostname connection_pool_kwargs["assert_hostname"] = result.hostname # overwrite the host header request.headers["Host"] = result.hostname else: # theses headers from a previous request may have been left #connection_pool_kwargs.pop("server_hostname", None) #python2 需要屏蔽掉 connection_pool_kwargs.pop("assert_hostname", None) return super(HostHeaderSSLAdapter, self).send(request, **kwargs)#使用--------------------------------------------------------------------------> url = "https://nginxtest.com/healthcheck" session = requests.Session() session.mount("https://", HostHeaderSSLAdapter("123.456.23.123")) try: r = session.get(url) except Exception as e: return "err : "+ str(e) if r.status_code != 200: return "not 200 " + "resp : "+ r.text
以上就是整个解决过程参考引用:https://www.zhihu.com/question/266700601/answer/2263452766https://stackoverflow.com/questions/22609385/python-requests-library-define-specific-dns