1

当我尝试使用请求加载外部 URL 的 django 视图时,我得到一个“模块”对象没有属性“create_connection”。但是,当我使用 urllib2 或来自交互式 shell 的相同请求代码时,它可以工作。

我的环境:

  • Python 2.5.2
  • 请求 0.10.0(我正在使用需要此版本的 3rd 方 api)
  • 在我的 django 站点的 virtualenv 中带有 WSGI 的 Apache
  • Django 1.4.1
  • Debian Linux 5
  • 我没有 SELinux(或任何类似的安全性)

我实际上为完全不同的功能使用了 2 个不同的 API。他们都需要请求,他们都给出了这个错误:

Exception Type: AttributeError
Exception Value: 'module' object has no attribute 'create_connection'
Exception Location: /my/virtualenv/dir/lib/python2.5/site-packages/requests/packages/urllib3/connectionpool.py in connect, line 67

异常中提到的行是:

sock = socket.create_connection((self.host, self.port), self.timeout)

看起来python 2.5附带的socket版本没有create_connection方法(它是在2.6中添加的)。但是,我尝试从 virtualenv 中的 python 交互式 shell 运行完全相同的代码,一切正常。此外,请求 0.10.0 应该适用于 python 2.5。

我创建了以下 2 个测试视图,因为我怀疑请求是问题的一部分:

def get_requests(request):
    import requests
    r = requests.get("https://google.ca")
    return HttpResponse(r.text)

def get_urllib(request):
    import urllib2
    r = urllib2.urlopen('https://google.ca')
    return HttpResponse(r.read())

urllib 视图有效,请求视图给了我与上面相同的错误。

urllib 工作的事实向我表明 Apache 有权连接到互联网(这不是防火墙问题)。

在尝试视图时,我已经完成了 tcpdump,并且请求甚至从未尝试连接。

有任何想法吗?请不要建议使用请求以外的东西,因为我正在使用 2 个需要它的不同的 3rd 方 API。

谢谢。

4

4 回答 4

1

看起来您在ssl安装了模块的 Python 2.5 中使用 HTTPS 的请求 0.10.0(或者,实际上是在 urllib3 中)遇到了一个错误。

如果您通过0.10.0 源进行跟踪,您可以看到如果ssl已安装并且您发出 HTTPS 请求,您将进入该VerifiedHTTPSConnection.connect方法。这也在HTTPSConnectionPool源代码的评论中进行了解释。但是您甚至不需要跟踪源,因为您已经从回溯中看到了这一点。

如果您查看该方法的源代码,它会无条件调用socket.create_connection,这在 2.5 中肯定会失败。

任何人修复此错误的可能性都非常小。看起来它是在 0.10.0 中引入的,而 0.10.1 仅通过放弃 2.5 支持来解决它。(我对此并不肯定,因为我在错误跟踪器中找不到它。)

所以你能对它做点啥?

首先,请注意,虽然create_connection是“更高级别” connect,但唯一真正的优势是它会在决定创建哪种套接字之前进行名称查找。如果您知道自己只关心 IPv4,则可以将其替换为:

self.sock = socket.socket()
self.sock.settimeout(self.timeout)
self.sock.connect((self.host, self.port))

如果你关心 IPv6,你可以借用2.6 代码create_connection代替。

所以,你有几个选择:

  • Fork 源代码和补丁urllib3.connectionpool.VerifiedHTTPConnection.connect以使用解决方法而不是create_connection.
  • 运行时的Monkeypatch urllib3.connectionpool.VerifiedHTTPConnection.connect
  • Monkeypatchsocket在运行时添加一个create_connection实现。

但是,鉴于历史,我不想保证 0.10.0 不会对 Python 2.5 产生进一步的问题。

于 2013-07-02T17:55:09.013 回答
0

从 0.10.1 开始,requests 放弃了对 Python 2.5 的支持。

升级您的 Python 或使用 requests 0.10.0 版本的请求。

0.10.1 (2012-01-23)

Python 3 支持!放弃 2.5 支持。(向后不兼容)

于 2013-07-02T01:11:53.267 回答
0

使用请求 0.9.3。这肯定适用于 Python 2.5。我们需要 Python 2.5 支持,要么 Kenneth 告诉我们使用那个版本,要么那是我们发现在实践中实际工作的最新版本。如果您需要重新使用该版本,请注意任何 API 差异。

于 2013-07-02T05:16:54.830 回答
0

正如 abarnert指出的,这是由请求 0.10.0 中的错误引起的,并且由于版本 0.10.1 中删除了 python 2.5 支持,因此无法修复。

所以我编辑了这个文件 requests/packages/urllib3/connectionpool.py (在第 67 行)。

原行:

    sock = socket.create_connection((self.host, self.port), self.timeout)

我将其替换为:

    try:
        sock = socket.create_connection((self.host, self.port), self.timeout)
    except AttributeError:
        # python 2.5 fix
        sock = socket.socket()
        if self.timeout is not None:
            sock.settimeout(self.timeout)
        sock.connect((self.host, self.port))

有了这个变化,一切都正常了。

于 2013-07-02T21:01:59.563 回答