当我try 使用Python中的requests库从AWS Lambda函数向未解析的域名发出HTTP请求时,我遇到了一个奇怪的行为.

当我try 使用以下命令发出请求时:

response = requests.get('https://Benandjerry.com', timeout=(1,1))

在AWS Lambda中,它始终需要大约10秒的时间才会抛出错误.然而,当我在我的本地环境中运行相同的代码时,它是瞬间的.我已经使用日志(log)和独立测试验证了这一点.

我考虑过Lambda冷启动、Lambda运行时差异甚至vPC配置等潜在问题,但似乎都不是根本原因.

我还try 使用cURL访问该域,它立即返回无法解析host:Benandjerry.com.

最后一点,这种情况发生在特定的未解析域名上,而不是所有域名上.

以下是一个示例:

仅供参考,您可以通过在AWS上创建一个python3.9 Lambda并添加以下代码来轻松复制该问题:

import json
from botocore.vendored import requests
import urllib.request
import os

def lambda_handler(event, context):
    # TODO implement
    url = 'http://Benandjerry.com'
    try:
        response = requests.get(url, proxies=None,verify=False)
    except Exception as e:
        print(e)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

问题:

  1. 是什么原因导致AWS Lambda出现持续10秒的延迟 对于使用请求的无法解析的域?
  2. 我如何才能让AWS Lambda立即识别该域无法解析,类似于我本地计算机上的行为?

推荐答案

您看到的问题是由于AWS域名解析花费了长达10秒的时间.如果您想要更多地控制DNS解析,您可以实现一个自定义请求Transport Adapter来自己进行DNS解析-这允许您更好地自定义超时.

pip install dnspython
import urllib
import requests
import dns.resolver


class CustomDnsResolverHttpAdapter(requests.adapters.HTTPAdapter):
    def resolve(self, hostname):
        resolver = dns.resolver.Resolver(configure=False)
        resolver.timeout = 5
        resolver.lifetime = 5

        resolver.nameservers = [
            "1.1.1.1"  # cloudflare dns
            , "8.8.8.8" # google dns
            # , "169.254.78.1"  # aws dns
        ]

        answer = resolver.resolve(hostname, "A", lifetime=5)

        if len(answer) == 0:
            return None

        return str(answer[0])

    def send(self, request, **kwargs):
        connection_pool_kwargs = self.poolmanager.connection_pool_kw

        result = urllib.parse.urlparse(request.url)
        resolved_ip = self.resolve(result.hostname)

        if result.scheme == "https" and resolved_ip:
            request.url = request.url.replace(
                "https://" + result.hostname,
                "https://" + resolved_ip,
            )
            connection_pool_kwargs["server_hostname"] = result.hostname  # SNI
            connection_pool_kwargs["assert_hostname"] = result.hostname

            # overwrite the host header
            request.headers["Host"] = result.hostname
        else:
            # clear these headers if they were set in a previous TLS request
            connection_pool_kwargs.pop("server_hostname", None)
            connection_pool_kwargs.pop("assert_hostname", None)

            # overwrite the host header
            request.headers["Host"] = result.hostname

        return super(CustomDnsResolverHttpAdapter, self).send(request, **kwargs)



http_agent = requests.Session()
http_agent.mount("http://", CustomDnsResolverHttpAdapter())
http_agent.mount("https://", CustomDnsResolverHttpAdapter())

response = http_agent.get("https://benandjerry.com")

Python相关问答推荐

Python如何让代码在一个程序中工作而不在其他程序中工作

两极:如何分割一个大 pyramid 并并行保存每个

Altair -箱形图边界设置为黑色,中线设置为红色

将从Python接收的原始字节图像数据转换为C++ Qt QIcon以显示在QStandardProject中

了解shuffle在NP.random.Generator.choice()中的作用

已删除的构造函数调用另一个构造函数

Python:记录而不是在文件中写入询问在多文件项目中记录的最佳实践

如何在PIL、Python中对图像应用彩色面膜?

Class_weight参数不影响RandomForestClassifier不平衡数据集中的结果

三个给定的坐标可以是矩形的点吗

为什么符号没有按顺序添加?

scikit-learn导入无法导入名称METRIC_MAPPING64'

运行终端命令时出现问题:pip start anonymous"

从groupby执行计算后创建新的子框架

我的字符串搜索算法的平均时间复杂度和最坏时间复杂度是多少?

在pandas数据框中计算相对体积比指标,并添加指标值作为新列

Python Tkinter为特定样式调整所有ttkbootstrap或ttk Button填充的大小,适用于所有主题

在代码执行后关闭ChromeDriver窗口

判断Python操作:如何从字面上得到所有decorator ?

Django Table—如果项目是唯一的,则单行