最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

Python requests库指定IP请求,并使用HTTPS证书验证

来源:博客园


(资料图片仅供参考)

背景

运维同学通过网关平台下发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

关键词: 自动校验 不可避免 这个问题