WebSocket 连接到'wss://api-such.andsuch.xyz/graphql/'失败:WebSocket 握手期间出错:意外响应代码:400



我最近将正在进行的一个项目部署到生产中。我将DjangoChannelsGraphqlWs用于GraphQL订阅功能。并且我已经通过CCD_ 2建立了GraphQL Playground。本地一切都很好——没有任何问题——订阅也很好。然而,当我部署时,当我在Playground:中点击播放按钮时,我会收到以下错误

{
"error": "Could not connect to websocket endpoint wss://api-such.andsuch.xyz/graphql/. Please check if the endpoint url is correct."
}

在我的浏览器控制台上,上面写着

WebSocket connection to 'wss://api-such.andsuch.xyz/graphql/' failed: Error during WebSocket handshake: Unexpected response code: 400

需要注意的一点是,该应用程序已被固定化。它可能是从那里来的吗?我不这么认为,因为它在当地有效。以下是我的docker-compose文件的样子:

version: '3.7'
services:
nginx:
container_name: nginx
image: nginx
restart: always
depends_on:
- web
volumes:
- ./web/dev.nginx.template:/etc/nginx/conf.d/dev.nginx.template
- ./static:/static
- ./media:/media
ports:
- "8080:80"
networks:
- SOME_NETWORK
command: /bin/bash -c "envsubst "`env | awk -F = '{printf " $$%s", $$1}'`" < /etc/nginx/conf.d/dev.nginx.template > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"
web:
container_name: web
restart: always
build: ./web
networks:
- SOME_NETWORK
depends_on:
- postgres
- redis
volumes:
- ./web:/usr/src/app/
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- GRAPHQL_ENDPOINT=https://api-such.andsuch.xyz/graphql/
command: bash -c /start.sh
postgres:
container_name: postgres
restart: always
image: postgres:latest
networks:
- SOME_NETWORK
volumes:
- pgdata:/var/lib/postgresql/data/
redis:
container_name: redis
restart: always
image: redis:latest
networks:
- SOME_NETWORK
ports:
- "6379:6379"
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:
networks:
SOME_NETWORK:
name: SOME_NETWORK
driver: bridge

settings.py

...
...
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [(os.getenv('REDIS_HOST', 'redis'), os.getenv('REDIS_PORT', 6379))],
}
}
}
...
...

routing.py

application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter([
path('graphql/', GraphQLWSConsumer)
]),
)
})

consumers.py

class GraphQLWSConsumer(channels_graphql_ws.GraphqlWsConsumer):
schema = schema
async def on_connect(self, payload):
self.scope['user'] = await get_user(self.scope)

urls.py

...
...
from graphql_playground.views import GraphQLPlaygroundView
urlpatterns = [
path('admin/', admin.site.urls),
path('playground/', GraphQLPlaygroundView.as_view(
endpoint=os.getenv('GRAPHQL_ENDPOINT'))),
]
...

nginx

server {
client_max_body_size 10M; 

listen 443 ssl;
listen [::]:443 ssl;

server_name api-such.andsuch.xyz;

ssl_certificate /etc/ssl/certs/andsuch.xyz.pem;
ssl_certificate_key /etc/ssl/certs/andsuch.xyz.key;

location = /favicon.ico { access_log off; log_not_found off; }

location / {
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection ‘upgrade’;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://0.0.0.0:8080;
}
}

可能出了什么问题?我没主意了。谢谢

更新我检查了chrome开发人员控制台中的"网络"选项卡,发现websocket连接立即关闭。为什么会发生这种情况?

您缺少routing.py文件;例如:

from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter
from . import consumers

application = ProtocolTypeRouter({
"websocket": URLRouter([
path("api-such.andsuch.xyz/graphql/", consumers.MyGraphqlConsumer),
]),
})

虽然urls.py声明了所有已发布的HTTP端点,但对于其他协议(尤其是websocket(,您应该使用routing.py

在负责处理所有websocket事件的Consumer中,您应该立即accept传入连接,因为这是协议所要求的:

from channels.consumer import SyncConsumer
class MyGraphqlConsumer(SyncConsumer):
def websocket_connect(self, event):
self.send({
'type': 'websocket.accept'
})

否则,连接将在短时间超时后失败。

在阅读了大量文章后,我发现了使用Postgres、Gunicorn和Nginx对Django进行Dockerializing,而关于Nginx的部分让我意识到,唯一错误的是我没有在内部向其他docker服务公开8000端口。

在我的docker-compose文件中,web服务应该具有以下内容,这解决了问题。

expose:
- 8000

相关内容

  • 没有找到相关文章

最新更新