【问题标题】:DRF + CoreAPIClient + psycopg2 throws exception, Interface error: connection already closedDRF + CoreAPIClient + psycopg2 抛出异常,接口错误:连接已关闭
【发布时间】:2018-09-23 23:54:17
【问题描述】:

我正在为使用 Django Rest Framework 和 Django 1.11 构建的 Web API 编写一些集成测试。当我使用 DRF 的 APIClient 向我的 API 端点发送请求时,我的测试通过了,但是当我使用 CoreAPIClient 时,请求会引发异常并返回内部服务器错误。但是,如果我使用 Postman,甚至是 coreapi-cli 命令,它就可以正常工作。

我的测试代码:

这行得通:

from rest_framework.test import APITestCase, APIClient

self.client = APIClient()
account_params = {
    'email': 'test1@example.com',
    'username': 'testuser1',
    'password': 'test1password'
}
account_response = self.client.post(reverse('account-list'), data=account_params)

但使用核心api客户端不起作用:

from rest_framework.test import APITestCase, CoreAPIClient

self.client = CoreAPIClient()
self.schema = self.client.get('http://localhost/api/schema')
params = {
    'email': 'test3@example.com',
    'username': 'testuser3',
    'password': 'test3password'
}
self.test_user = self.client.action(self.schema, ['accounts', 'create'], params=params)

这是我得到的例外:

Error
Traceback (most recent call last):
  File "/home/pitt/dev/cps/cps_mono/surveys/tests.py", line 429, in setUp
    self.test_user = self.client.action(self.schema, ['accounts', 'create'], params=params)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/coreapi/client.py", line 178, in action
    return transport.transition(link, self.decoders, params=params, link_ancestors=link_ancestors)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/coreapi/transports/http.py", line 386, in transition
    raise exceptions.ErrorMessage(result)
coreapi.exceptions.ErrorMessage: <Error: 500 Internal Server Error>
    message: "<h1>Server Error (500)</h1>"

我打开了DEBUG_PROPAGATE_EXCEPTIONS 标志,现在可以更详细地了解异常抛出:

Error
Traceback (most recent call last):
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/backends/base/base.py", line 231, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/backends/postgresql/base.py", line 220, in create_cursor
    cursor = self.connection.cursor()
psycopg2.InterfaceError: connection already closed

The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/home/pitt/dev/cps/cps_mono/surveys/tests.py", line 429, in setUp
    self.test_user = self.client.action(self.schema, ['accounts', 'create'], params=params)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/coreapi/client.py", line 178, in action
    return transport.transition(link, self.decoders, params=params, link_ancestors=link_ancestors)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/coreapi/transports/http.py", line 379, in transition
    response = session.send(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/requests/sessions.py", line 618, in send
    r = adapter.send(request, **kwargs)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/test.py", line 98, in send
    wsgi_response = self.app(environ, start_response)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/wsgi.py", line 157, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/base.py", line 124, in get_response
    response = self._middleware_chain(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/deprecation.py", line 140, in __call__
    response = self.get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = response_for_exception(request, exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 93, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/viewsets.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/views.py", line 483, in dispatch
    response = self.handle_exception(exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/views.py", line 443, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/views.py", line 480, in dispatch
    response = handler(request, *args, **kwargs)
  File "/home/pitt/dev/cps/cps_mono/accounts/views.py", line 38, in create
    if serializer.is_valid(raise_exception=True):
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/serializers.py", line 236, in is_valid
    self._validated_data = self.run_validation(self.initial_data)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/serializers.py", line 434, in run_validation
    value = self.to_internal_value(data)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/serializers.py", line 488, in to_internal_value
    validated_value = field.run_validation(primitive_value)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/fields.py", line 776, in run_validation
    return super(CharField, self).run_validation(data)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/fields.py", line 524, in run_validation
    self.run_validators(value)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/fields.py", line 538, in run_validators
    validator(value)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/validators.py", line 81, in __call__
    if qs_exists(queryset):
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/rest_framework/validators.py", line 24, in qs_exists
    return queryset.exists()
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/models/query.py", line 670, in exists
    return self.query.has_results(using=self.db)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/models/sql/query.py", line 517, in has_results
    return compiler.has_results()
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 858, in has_results
    return bool(self.execute_sql(SINGLE))
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/models/sql/compiler.py", line 887, in execute_sql
    cursor = self.connection.cursor()
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/backends/base/base.py", line 254, in cursor
    return self._cursor()
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/backends/base/base.py", line 231, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/backends/base/base.py", line 231, in _cursor
    return self._prepare_cursor(self.create_cursor(name))
  File "/home/pitt/.virtualenvs/cps_mono/lib/python3.5/site-packages/django/db/backends/postgresql/base.py", line 220, in create_cursor
    cursor = self.connection.cursor()
django.db.utils.InterfaceError: connection already closed

当我在我的序列化程序上调用 .is_valid() 以验证传入数据时,我逐步检查了我的代码以查找异常的来源,它似乎在 Django 服务器端。然而,这只发生在我使用 Django REST Framework 提供的 CoreAPIClient 时。

任何想法可能是什么问题?

更新:

我通过虚拟环境和 pycharm 在本地运行测试。我的数据库在 docker 容器中作为远程数据库运行。我在 docker 网络上的本地机器和 docker 主机的本地 IP 是 172.18.0.1,我将它添加到了配置文件中。 这是我的pg_hba.conf 文件中的内容

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
host    all             all             172.18.0.1/32           trust
# IPv6 local connections:
host    all             all             ::1/128                 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local   replication     postgres                                trust
#host    replication     postgres        127.0.0.1/32            trust
#host    replication     postgres        ::1/128                 trust

host all all all md5

更新 2:

查看数据库日志后,我可以确认至少完成了 CoreAPIClient 测试的部分设置。创建了测试数据库,并且在再次关闭连接之前完全执行了迁移(如预期的那样)。所以 Django 和数据库容器之间的初始连接是有效的。

我还尝试从 API 容器内部运行测试套件,但它会引发相同的错误。所以docker主机和Django容器之间的连接不是问题。

单步执行代码我还看到 CoreAPIRequest 确实登陆了后端,并且正在执行端点的代码。但是,Django 似乎无法打开新的数据库连接来运行任何查询。为什么会这样呢?

【问题讨论】:

  • 您是否检查了您的pg_hba.conf 文件中是否允许本地连接? postgresql.org/docs/9.3/static/auth-pg-hba-conf.html
  • @JacquesGaudin 是的,允许本地连接。我正在使用docker运行一个postgresql容器顺便说一句。我将本地机器 / docker 主机的 IP 地址添加到 pg_hba.conf 文件中,但不幸的是它并没有解决问题。正如我在问题中提到的,api端点和db连接正常工作,只是当我使用CoreAPIClient时它会抛出这个异常。
  • 听起来您可以访问您的应用程序的网络层,但不能访问接口层。这就是为什么我认为您在pg_hba.conf 中没有以local 开头的行。您是否使用远程数据库从本地计算机运行测试代码?
  • @JacquesGaudin 我已经用我的pg_hba.conf 文件的内容更新了这个问题。它已经在接受所有本地流量。 CoreAPIClient 代码中一定存在导致数据库连接断开的内容。

标签: python django django-rest-framework psycopg2 core-api


【解决方案1】:

这似乎是一个代码问题,您使用的是 django-cors-headers 和新的基于开放 api 的解决方案吗?核心 API 现在有点过时了。

500 内部服务器错误是“服务器端”错误,这意味着问题不在于您的 PC 或 Internet 连接,而是网站服务器的问题。 ...所以问题肯定出在您使用的服务器上。

【讨论】:

    【解决方案2】:

    我建议使用rest_framework.test.APITransactionTestCase 而不是rest_framework.test.APITestCase

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-11
      • 2012-03-14
      • 2013-03-14
      • 2017-04-18
      • 1970-01-01
      • 2015-07-27
      • 2011-01-29
      • 1970-01-01
      相关资源
      最近更新 更多