强制要求使用IPv4/IPv6

omi*_*nug 8 python python-requests

如何强制requests库使用特定的Internet协议版本来获取get请求?或者这可以通过Python中的另一种方法更好地实现?我可以,但我不想用curl...

澄清目的的例子:

import requests
r = requests.get('https://my-dyn-dns-service.domain/?hostname=my.domain',
                 auth = ('myUserName', 'my-password'))
Run Code Online (Sandbox Code Playgroud)

Ker*_*ley 25

您可以使用此 hack 来强制requests使用 IPv4:

requests.packages.urllib3.util.connection.HAS_IPV6 = False
Run Code Online (Sandbox Code Playgroud)

(这是 Nulano 作为评论提交的,我认为它应该是一个正确的答案)。

  • 最简洁的解决方案,尽管它是全局配置的。 (4认同)

小智 7

我发现了一种强制urrlib3使用ipv4或ipv6的简约解决方案。urrlib3使用此方法为Http和Https创建新连接。您可以在其中指定要使用的任何AF_FAMILY。

import socket
import requests.packages.urllib3.util.connection as urllib3_cn


  def allowed_gai_family():
    """
     https://github.com/shazow/urllib3/blob/master/urllib3/util/connection.py
    """
    family = socket.AF_INET
    if urllib3_cn.HAS_IPV6:
        family = socket.AF_INET6 # force ipv6 only if it is available
    return family

urllib3_cn.allowed_gai_family = allowed_gai_family
Run Code Online (Sandbox Code Playgroud)

  • 为了始终强制使用 IPv4,“requests.packages.urllib3.util.connection.HAS_IPV6 = False”似乎对我有用。 (17认同)

ntn*_*nja 6

我已经为requests+ urllib3+编写了一个运行时补丁socket,允许根据每个请求选择性地传递所需的地址族。

\n\n

与其他解决方案不同,不涉及猴子修补,而是requests用修补的文件替换导入,并且它提供了一个request兼容的接口,其中所有公开的类都被子类化和修补,并且所有 \xe2\x80\x9csimple API\xe2\x80\x9d 函数都被重新实现。唯一明显的区别应该是存在一个额外的family参数,您可以使用它来将名称解析过程中使用的地址族限制为socket.AF_INETsocket.AF_INET6。然后,使用一系列有点复杂(但大多只是 LoC 密集型)的策略方法覆盖来将该值一直传递到底层,以便urllib3在函数调用的替代实现中使用该值socket.create_connection

\n\n

TL;DR用法如下:

\n\n
import socket\n\nfrom . import requests_wrapper as requests  # Use this load the patch\n\n\n# This will work (if IPv6 connectivity is available) \xe2\x80\xa6\nrequests.get("http://ip6only.me/", family=socket.AF_INET6)\n# \xe2\x80\xa6 but this won\'t\nrequests.get("http://ip6only.me/", family=socket.AF_INET)\n\n# This one will fail as well\nrequests.get("http://127.0.0.1/", family=socket.AF_INET6)\n\n# This one will work if you have IPv4 available\nrequests.get("http://ip6.me/", family=socket.AF_INET)\n\n# This one will work on both IPv4 and IPv6 (the default)\nrequests.get("http://ip6.me/", family=socket.AF_UNSPEC)\n
Run Code Online (Sandbox Code Playgroud)\n\n

补丁库的完整链接(~350 LoC): https: //gitlab.com/snippets/1900824

\n


小智 5

这是一个hack,但是您可以monkey-patch getaddrinfo来仅过滤IPv4地址:

# Monkey patch to force IPv4, since FB seems to hang on IPv6
import socket
old_getaddrinfo = socket.getaddrinfo
def new_getaddrinfo(*args, **kwargs):
    responses = old_getaddrinfo(*args, **kwargs)
    return [response
            for response in responses
            if response[0] == socket.AF_INET]
socket.getaddrinfo = new_getaddrinfo
Run Code Online (Sandbox Code Playgroud)


Foo*_*oon 1

这完全未经测试,可能需要一些调整,但是结合使用 Python \xe2\x80\x9crequests\xe2\x80\x9d 与现有套接字连接以及如何强制 python httplib 库仅使用 A requests 的答案,看起来像你应该能够创建一个仅 IPv6 的套接字,然后让请求将其用于其连接池,如下所示:

\n\n
try:\n    from http.client import HTTPConnection\nexcept ImportError:\n    from httplib import HTTPConnection\n\nclass MyHTTPConnection(HTTPConnection):\n    def connect(self):\n        print("This actually called called")\n        self.sock = socket.socket(socket.AF_INET6)\n        self.sock.connect((self.host, self.port,0,0))\n        if self._tunnel_host:\n            self._tunnel()\n\nrequests.packages.urllib3.connectionpool.HTTPConnection = MyHTTPConnection\n
Run Code Online (Sandbox Code Playgroud)\n