在使用python开发的时候,发现requests能请求到数据,而aiohttp需要指定dns才能获取数据。

这个问题是因为 aiohttp 默认使用 AsyncResolver(基于 aiodns),它需要系统 DNS 配置支持。而 requests 使用的是系统默认的 DNS 解析方式(通常是阻塞式的 socket 解析)。

以下是几种解决方案:

方案1:使用 ThreadedResolver(推荐)

最简单的方案是让 aiohttp 使用和 requests 类似的线程 DNS 解析器:

import aiohttp
import asyncio

async def fetch_data():
    # 使用 ThreadedResolver 替代默认的 AsyncResolver
    connector = aiohttp.TCPConnector(
        resolver=aiohttp.resolver.ThreadedResolver()
    )
    
    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get('http://example.com') as response:
            return await response.text()

# 使用
asyncio.run(fetch_data())

方案2:自定义 DNS 服务器

如果需要指定特定的 DNS 服务器:

import aiohttp
import asyncio
from aiohttp.resolver import AsyncResolver

async def fetch_data():
    # 指定 DNS 服务器,例如使用 Google DNS
    resolver = AsyncResolver(nameservers=["8.8.8.8", "8.8.4.4"])
    connector = aiohttp.TCPConnector(resolver=resolver)
    
    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get('http://example.com') as response:
            return await response.text()

asyncio.run(fetch_data())

方案3:安装并配置 aiodns

确保正确安装了 aiodns 和 pycares:

pip install aiodns pycares

然后在代码中可能还需要配置:

import aiohttp
import asyncio

async def fetch_data():
    # 可以设置超时时间
    timeout = aiohttp.ClientTimeout(total=10)
    
    async with aiohttp.ClientSession(timeout=timeout) as session:
        async with session.get('http://example.com') as response:
            return await response.text()

asyncio.run(fetch_data())

方案4:全局设置(所有请求生效)

如果想让整个应用都使用 ThreadedResolver:

import aiohttp
import asyncio

class CustomClientSession(aiohttp.ClientSession):
    def __init__(self, *args, **kwargs):
        connector = aiohttp.TCPConnector(
            resolver=aiohttp.resolver.ThreadedResolver()
        )
        super().__init__(connector=connector, *args, **kwargs)

# 使用自定义 Session
async def fetch_data():
    async with CustomClientSession() as session:
        async with session.get('http://example.com') as response:
            return await response.text()

asyncio.run(fetch_data())

推荐解决方案

对于大多数情况,方案1(ThreadedResolver) 是最简单且兼容性最好的解决方案,因为它使用与 requests 相同的方式解析 DNS,只是在线程池中执行以避免阻塞。如果性能要求较高且 DNS 解析频繁,可以考虑方案2,指定可靠的公共 DNS 服务器。