使用IP访问https服务

更新时间:2025-02-06 05:09:29

远程VPC服务仅支持使用域名访问,直接使用IP访问会导致错误使请求失败。本文将介绍通过将域名添加到请求Host中,以便通过IP地址访问HTTPS服务,来满足SparkUDF等任务的远程访问需求。

直接使用IP访问HTTPS服务失败

报错信息

SSL: no alternative certificate subject name matches target host name '47.116.XX.XX'
More details here: https://curl.haxx.se/docs/sslcerts.html 
curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. 
To learn more about this situation and how to fix it, please visit the web page mentioned above.

问题描述

SparkUDF等任务,访问远程VPC服务,比如KMS、OSS等。在此过程中需要使用HTTPS功能,如果直接通过IP来访问对端服务会报上述错误信息。

解决方案

将域名添加到请求的host中,以解决通过IP直接访问HTTPS服务时所遇到的IP无法通过SSL证书验证的问题。

1. 获取远程服务的IP信息。

ping命令获取
dig命令获取

WindowsLinux的控制台,直接输入如下指令,并获取远程服务IP。

ping service.cn-shanghai-vpc.maxcompute.aliyun-inc.com
  • Windows环境返回结果如下:

    tt

  • Linux环境返回结果如下:

    yy

  1. Windows环境或Linux环境下安装Bind-utils。

    • Windows环境

      下载BIND9.17.12.x64.zip并解压至指定目录,例如D:\install\BIND9.17.12.x64。在Windows环境变量Path中添加此路径即可。

    • Linux环境(CentOS)

      直接在Linux操作控制台输入指令sudo yum install bind-utils完成安装即可。

  2. 在各自环境的控制台执行如下指令:

    dig service.cn-shanghai-vpc.maxcompute.aliyun-inc.com

    返回结果如下:

    Windows环境
    Linux环境

    ppp

    123h

2. 配置IP信息。

您可以根据Python不同版本,参考如下代码,在发送请求的access_url中添加IP信息。在正式发布任务之前,可先在对应网络环境进行远程访问测试。

  • python2

    # _*_ coding: utf-8 _*_
    # only for python2
    import requests
    from urlparse import urlparse
    
    class HostHeaderSSLAdapter(requests.adapters.HTTPAdapter):
        def __init__(self, resolved_ip):
            super(HostHeaderSSLAdapter,self).__init__()
            self.resolved_ip = resolved_ip
    
        def send(self, request, **kwargs):
            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['assert_hostname'] = result.hostname
                request.headers['Host'] = result.hostname
            else:
                connection_pool_kwargs.pop('assert_hostname', None)
    
            return super(HostHeaderSSLAdapter, self).send(request, **kwargs)
    
    def access_url(url, resolved_ip):
        session = requests.Session()
        # 从url中获取域名部分
        parsed_url = urlparse(url)
        hostname = parsed_url.hostname
    
        session.mount('https://'+hostname, HostHeaderSSLAdapter(resolved_ip))
        try:
            r = session.get(url)
        except Exception as e:
            print("err : "+ str(e))
        else:
            if r.status_code != 200:
                print("not 200 " + ",resp : "+ r.text)
            else:
                print("success" + ",resp : "+ r.text)
    
    if __name__ == "__main__":
        # ip通过dig域名获取,需要在vpc环境内dig
        # vpc地址测试
        #access_url("https://service.cn-shanghai-vpc.maxcompute.aliyun-inc.com", "100.103.104.45")
        # 公网地址测试
        access_url("https://service.cn-shanghai.maxcompute.aliyun.com", "47.116.XX.XX")
  • python3

    # _*_ coding: utf-8 _*_
    import requests
    from urllib.parse import urlparse 
    
    class HostHeaderSSLAdapter(requests.adapters.HTTPAdapter):
        def __init__(self, resolved_ip):
            super().__init__()                                        
            self.resolved_ip = resolved_ip
    
        def send(self, request, **kwargs):
            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  
                # 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)           
            return super().send(request, **kwargs)
    
    def access_url(url, resolved_ip):
        session = requests.Session()
        # 从url中获取域名部分
        parsed_url = urlparse(url)
        hostname = parsed_url.hostname
    
        session.mount('https://'+hostname, HostHeaderSSLAdapter(resolved_ip))
        try:
            r = session.get(url)
        except Exception as e:
            print("err : "+ str(e))
        else:
            if r.status_code != 200:
                print("not 200 " + ",resp : "+ r.text)
            else:
                print("success" + ",resp : "+ r.text)
    
    if __name__ == "__main__":
        # ip通过dig域名获取,需要在vpc环境内dig
        # vpc地址测试
        #access_url("https://service.cn-shanghai-vpc.maxcompute.aliyun-inc.com", "100.103.104.45")
        # 公网地址测试
        access_url("https://service.cn-shanghai.maxcompute.aliyun.com", "47.116.XX.XX")

测试结果

说明

若您需要访问VPC网络的相关实例服务,请在VPC网络环境下,配置Python环境,替换实例服务所在VPC网络链接和IP地址进行测试。

  • 在本地通过公网访问MaxCompute服务。

    fartestsss

  • Linux云服务器上通过公网访问MaxCompute服务。

    yyyrtqerewr

  • 本页导读 (1)
  • 直接使用IP访问HTTPS服务失败
  • 报错信息
  • 问题描述
  • 解决方案
  • 测试结果
AI助理

点击开启售前

在线咨询服务

你好,我是AI助理

可以解答问题、推荐解决方案等