Airflow的SimpleHttpOperator不支持https问题解决

简介:

首先创建一个SimpleHttpOperator

http_test_operator = SimpleHttpOperator(
    http_coon_id='http_test_1',
    endpoint='https://free-api.heweather.com/s6/weather/forecast?unit=m&location=北京&lang=zh&key=*******************',
    method='GET',
    response_check=http_resp_check,
)

在测试的时候发现问题如下:

[2018-04-27 11:58:31,880] {http_hook.py:77} INFO - Sending 'GET' to url: https://www.google.com/s6/weather/forecast?unit=m&location=朝阳,北京&lang=zh&key=*********

很明显url和我们想的不一样,查询官方文档得到如下解释:

    Airflow还能够通过操作系统的环境变量来引用连接。环境变量需要加上前缀AIRFLOW_CONN_才能被视为连接。在Airflow管道中引用连接时,conn_id应该是没有前缀的变量的名称。例如,如果conn_id 名为postgres_master环境变量应该被命名 AIRFLOW_CONN_POSTGRES_MASTER(注意环境变量必须全部为大写)。Airflow假定从环境变量返回的值是URI格式(例如 postgres://user:password@localhost:5432/master或s3://accesskey:secretkey@S3)。

airflow会首先根据conn_id在环境变量中寻找对应的host,如果没有则使用默认的,数据库中connection表的http_default的host值:https://www.google.com/

于是先设置环境变量吧

export AIRFLOW_CONN_WEATHER=https://free-api.heweather.com/

并修改代码中endpoint参数如下:

http_test_operator = SimpleHttpOperator(
    http_coon_id='http_test_1',
    endpoint='/s6/weather/forecast?unit=m&location=北京&lang=zh&key=*******************',
    method='GET',
    response_check=http_resp_check,
)

继续测试,发现调试信息如下:

[2018-04-27 12:21:13,131] {http_hook.py:77} INFO - Sending 'GET' to url: http://free-api.heweather.com/s6/weather/forecast?unit=m&location=北京&lang=zh&key=********************

我们明明设置的https://,怎么变成了http://

查看源码

class HttpHook(BaseHook):

    def get_conn(self, headers):
        """
        Returns http session for use with requests
        """
        conn = self.get_connection(self.http_conn_id)
        session = requests.Session()

        if "://" in conn.host:
            self.base_url = conn.host
        else:
            # schema defaults to HTTP
            schema = conn.schema if conn.schema else "http"
            self.base_url = schema + "://" + conn.host

实际请求的正是这个self.base_url,那么这个conn.schema是哪来的呢?

class BaseHook(LoggingMixin):
    @classmethod
    def get_connections(cls, conn_id):
        conn = cls._get_connection_from_env(conn_id)
        if conn:
            conns = [conn]
        else:
            conns = cls._get_connections_from_db(conn_id)
        return conns

其实到这里已经看到我们的环境变量是怎么起作用了,也看到了如果环境变量没有设置,是会从数据库中选择的。在数据库中connection表的schema字段正是我们要找的。

    @classmethod
    def _get_connection_from_env(cls, conn_id):
        environment_uri = os.environ.get(CONN_ENV_PREFIX + conn_id.upper())
        conn = None
        if environment_uri:
            conn = Connection(conn_id=conn_id, uri=environment_uri)
        return conn

在这个地方,我们明显可以看到官方文档中的描述(环境变量的设置)是如何被执行的。

class Connection(Base, LoggingMixin):    
    def __init__(
            self, conn_id=None, conn_type=None,
            host=None, login=None, password=None,
            schema=None, port=None, extra=None,
            uri=None):
        self.conn_id = conn_id
        if uri:
            self.parse_from_uri(uri)
        else:
            self.conn_type = conn_type
            self.host = host
            self.login = login
            self.password = password
            self.schema = schema
            self.port = port
            self.extra = extra  
            
    def parse_from_uri(self, uri):
        temp_uri = urlparse(uri)
        hostname = temp_uri.hostname or ''
        if '%2f' in hostname:
            hostname = hostname.replace('%2f', '/').replace('%2F', '/')
        conn_type = temp_uri.scheme
        if conn_type == 'postgresql':
            conn_type = 'postgres'
        self.conn_type = conn_type
        self.host = hostname
        self.schema = temp_uri.path[1:]
        self.login = temp_uri.username
        self.password = temp_uri.password
        self.port = temp_uri.port

到这里基本上就明白了schema是哪里来的

self.schema = temp_uri.path[1:]

这是什么意思?难道我要写成"https://free-api.heweather.com/https"

各位看官,到这里基本上我们就明白问题所在了

你可以修改这里的源码为

self.schema = conn_type

进行测试。

也可以写成

环境变量也可以设置为"https://free-api.heweather.com/https"

如果你的airflow版本和我的不同,源码可能是下面这个样子:

    # headers is required to make it required
    def get_conn(self, headers):
        """
        Returns http session for use with requests
        """
        conn = self.get_connection(self.http_conn_id)
        session = requests.Session()
        self.base_url = conn.host
        if not self.base_url.startswith('http'):
            self.base_url = 'http://' + self.base_url

        if conn.port:
            self.base_url = self.base_url + ":" + str(conn.port) + "/"
        if conn.login:
            session.auth = (conn.login, conn.password)
        if headers:
            session.headers.update(headers)

        return session

关键在这里

        self.base_url = conn.host
        if not self.base_url.startswith('http'):
            self.base_url = 'http://' + self.base_url

这里的判断条件(not self.base_url.startswith('http'))必然为真,所以只会拼接“http://”(头大)

除了更改环境变量或者上述代码还要更改代码如下:

def get_conn(self, headers):
        """
        Returns http session for use with requests
        """
        conn = self.get_connection(self.http_conn_id)
        session = requests.Session()
        self.base_url = '{}://{}'.format(conn.sharem, conn.host)
        # if not self.base_url.startswith('http'):
        #     self.base_url = 'http://' + self.base_url

        if conn.port:
            self.base_url = self.base_url + ":" + str(conn.port) + "/"
        if conn.login:
            session.auth = (conn.login, conn.password)
        if headers:
            session.headers.update(headers)
        return session

注意:这样是没有添加证书验证的!

运行会警告:

/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py:858: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings

运行结果:

{'HeWeather6': [{'basic': {'cid': 'CN101010300', 'location': '朝阳', 'parent_city': '北京', 'admin_area': '北京', 'cnty': '中国', 'lat': '39.92148972', 'lon': '116.48641205', 'tz': '+8.00'}, 'update': {'loc': '2018-04-27 17:47', 'utc': '2018-04-27 09:47'}, 'status': 'ok', 'daily_forecast': [{'cond_code_d': '100', 'cond_code_n': '100', 'cond_txt_d': '晴', 'cond_txt_n': '晴', 'date': '2018-04-27', 'hum': '40', 'mr': '16:06', 'ms': '04:04', 'pcpn': '0.0', 'pop': '0', 'pres': '1021', 'sr': '05:20', 'ss': '19:04', 'tmp_max': '27', 'tmp_min': '13', 'uv_index': '7', 'vis': '10', 'wind_deg': '0', 'wind_dir': '无持续风向', 'wind_sc': '1-2', 'wind_spd': '7'}, {'cond_code_d': '100', 'cond_code_n': '100', 'cond_txt_d': '晴', 'cond_txt_n': '晴', 'date': '2018-04-28', 'hum': '41', 'mr': '17:11', 'ms': '04:35', 'pcpn': '0.0', 'pop': '0', 'pres': '1013', 'sr': '05:18', 'ss': '19:05', 'tmp_max': '27', 'tmp_min': '16', 'uv_index': '8', 'vis': '20', 'wind_deg': '188', 'wind_dir': '南风', 'wind_sc': '1-2', 'wind_spd': '7'}, {'cond_code_d': '101', 'cond_code_n': '305', 'cond_txt_d': '多云', 'cond_txt_n': '小雨', 'date': '2018-04-29', 'hum': '43', 'mr': '18:15', 'ms': '05:07', 'pcpn': '0.0', 'pop': '0', 'pres': '1005', 'sr': '05:17', 'ss': '19:06', 'tmp_max': '30', 'tmp_min': '18', 'uv_index': '8', 'vis': '20', 'wind_deg': '181', 'wind_dir': '南风', 'wind_sc': '1-2', 'wind_spd': '10'}]}]}
目录
相关文章
|
前端开发 应用服务中间件 Linux
nginx支持一个端口访问多个前端项目(http以及https)
最近做项目结构优化,前端项目都是部署在nginx上,想实现同一个端口可以访问多个前端项目.
|
运维 Java 应用服务中间件
Spring Boot 支持 HTTPS 如此简单,So easy!
Spring Boot 支持 HTTPS 如此简单,So easy!
2176 0
Spring Boot 支持 HTTPS 如此简单,So easy!
|
负载均衡 Kubernetes 安全
服务网格ASM使用FAQ之(5):ASM网关支持在SLB侧创建HTTPS类型的监听
ASM网关提供HTTPS安全支持、证书动态加载,从而提升ASM网关安全性。除了在ASM网关侧绑定证书的方式之外, 还可以在负载均衡侧管理证书。 本文介绍如何支持ASM网关服务在负载均衡侧绑定证书, 并创建HTTPS类型的监听。
297 0
|
PHP
解决阿里云虚拟主机上WordPress配置支持Https
解决阿里云虚拟主机上WordPress配置支持Https
156 0
解决阿里云虚拟主机上WordPress配置支持Https
|
应用服务中间件 Linux 网络安全
nginx安装配置ssl模块支持https访问
nginx安装配置ssl模块支持https访问
252 0
nginx安装配置ssl模块支持https访问
|
安全 Java 数据建模
Nginx如何支持HTTPS?手把手教会你每一步操作都贼简单
随着我们网站用户的增多,我们会逐渐意识到HTTPS加密的重要性。在不修改现有代码的情况下,要从HTTP升级到HTTPS,让Nginx支持HTTPS是个很好的选择。今天我们来讲下如何从Nginx入手,从HTTP升级到HTTPS,同时支持静态网站和SpringBoot应用,希望对大家有所帮助! 生成SSL自签名证书 虽然自签名证书浏览器认为并不是安全的,但是学习下SSL证书的生成还是很有必要的! 首先创建SSL证书私钥,期间需要输入两次用户名和密码,生成文件为blog.key;
410 0
Nginx如何支持HTTPS?手把手教会你每一步操作都贼简单
|
负载均衡
新功能:阿里云负载均衡SLB支持HTTPS虚拟主机功能(SNI)
新功能:负载均衡SLB支持HTTPS虚拟主机功能(SNI)
5899 0
|
Java 应用服务中间件
一分钟开启Tomcat https支持
1、修改配置文件 打开tomcat/conf/server.xml配置文件,把下面这段配置注释取消掉,keystorePass为证书密钥需要手动添加,创建证书时指定的。
123 0
|
JavaScript 网络安全 Apache
使用openSSL构造一个支持https的nodejs服务器
使用openSSL构造一个支持https的nodejs服务器
138 0
使用openSSL构造一个支持https的nodejs服务器
|
安全 网络安全
宝塔面板如何配置网站ssl安全证书(支持https访问)
宝塔面板如何配置网站ssl安全证书(支持https访问)
3257 0