Using the Channels feature in Django
Preface: recently the background to write the game update version function, simply is the front-end send update request, the back-end needs to update many servers and a variety of operations, originally thought to achieve not difficult, then found that because the back-end needs to perform a long time, the front-end returns an error, the back-end will be executed, but the front-end first disconnected, so that in the front page I can not see the update results. By adjusting the nginx parameters, set the timeout time, or the log will report 499 status code error. Then I learned about websocket, and for requests that need to be processed for a long time, it is better to use websocket, and I implemented my own function by using websocket.
I. What is WebSocket
WebSocket is a protocol for full-duplex communication over a single TCP connection. webSocket allows the server to actively push data to the client.
In the WebSocket protocol, the client browser and server need to complete only one handshake to create a persistent connection and transfer data in both directions between the browser and the server.
Important fields in the response header of WebSocket.
HTTP/1.1 101 Swi tching Protocols: Switching protocols, the WebSocket protocol establishes TCP connections at the transport layer via the HTTP protocol
Connection and Upgrade: indicates the WebSocket response initiated by the server side
Sec-WebSocket-Accept: indicates that the server has accepted the client's request, as calculated by Sec-WebSocket-Key
Advantages of WebSocket protocol.
Support two-way communication, more real-time
Lightweight data format, low performance overhead, efficient communication
Support for extensions, users can extend the protocol or implement custom sub-protocols (e.g., support for custom compression algorithms, etc.)
Disadvantages of WebSocket protocol.
A small number of browsers do not support it, and there are differences in the degree and manner of browser support
Long connections require higher code stability for back-end processing, and back-end push functions are relatively complex
There are a large number of components that can be reused in a mature HTTP ecosystem, WebSocket is less
Application scenarios of WebSocket.
Live chat communication, website message notification
Online collaborative editing, such as Tencent documents
Multi-player online games, video pop-ups, stock fund implementation quotes
Second, what is Channels
Django itself does not support WebSocket, but can be implemented by integrating the Channels framework to WebSocket
Channels is an enhanced framework for the Django project , you can make Django not only support HTTP protocol , but also support WebSocket , MQTT and other protocols , while Channels also integrates Django auth and session system to facilitate user management and authentication .
2.1Channels files and configuration meaning
asgi.py: interface between the web protocol service and the Python application, capable of handling a variety of common protocol types, including HTTP, HTTP2 and WebSocket
channel_layers: configured in settings.py. Similar to a channel where the sender (producer) sends a message on one end and the consumer listens on the other
routings.py: equivalent to urls.py in Django
consumers.py: equivalent to Django's views.py
2.2channels documentation links
h ttps://channels.readthedocs.io/en/latest/introduction.html
2.3. WSGI and ASGI are different
WSGI (Python Web Server Gateway Interface): a simple and common interface between a web server and a web application or framework defined for the Python language.
ASGI (Asynchronous Web Server Gateway Interface): Asynchronous Gateway Protocol Interface, a standard interface between web protocol services and Python applications, capable of handling a variety of common protocol types, including HTTP, HTTP2 and WebSocket.
III. Using Channels in Django
3.1 Installing channels
pip install channels==2.1.7
3.2 Modify the setting.py file
INSTALLED_APPS = [
'django.contrib.staticfiles',
... ...
'channels',
]
# Specify the ASGI routing address
ASGI_APPLICATION = 'webapp.routing.application' #ASGI_APPLICATION specifies the location of the main route as the application in the routing.py file under webapp
3.3. Create routing.py in the same directory as setting.py. routing.py is similar to url.py in Django, which specifies the route for the websocket protocol
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
import webapp.routing
application = ProtocolTypeRouter({
'websocket': AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
webapp.routing.websocket_urlpatterns
)
)
)
})
ProtocolTypeRouter: ASGI supports many different protocols, here you can specify the routing information for a specific protocol, here only the websocket protocol is used, here only the websocket can be configured
AllowedHostsOriginValidator: specify the IPs allowed to access, after setting it, it will go to settings.py in Django to find the IPs set by ALLOWED_HOSTS
AuthMiddlewareStack: used for WebSocket authentication, inherits Cookie Middleware, SessionMiddleware, SessionMiddleware.
django's channels encapsulates django's auth module, using this configuration we can get the user's information, and the url path of the request in the consumer with the following code
def connect(self):
self.user = self.scope ["user" ]
self.request_url = self.scope ['path']
self.scope is similar to request in django and contains useful information about the request's type, path, header, cookie, session, user, etc.
URLRouter: specify the path to the routing file, you can also write the routing information directly here, the code configures the path to the routing file, it will go to the corresponding application under the routeing.py file to find the websocket_urlpatterns
3.4 The contents of webapp.routing.py are as follows
from django.urls import path
from webapp.consumers import ChatConsumer
websocket_urlpatterns = [
path ('ws/chat/', ChatConsumer)
websocket_urlpatterns = [ path('ws/chat/',ChatConsumer)
The routing.py routing file is similar to django's url.py and has the same syntax, meaning that access to ws/chat/ is handled by ChatConsumer.
3.5 Create consumers.py in the application that will use WebSocket. consumers.py is used to develop python applications with ASGI interface specification, while view.py in Django is used to develop python applications with WSGI interface specification.
from channels.generic.websocket import WebsocketConsumer
from channels.generic.websocket import AsyncWebsocketConsumer
import json,time
Channels supports both synchronous and asynchronous methods
The code for the synchronous method is as follows.
class ChatConsumer(WebsocketConsumer):
# websocket connection establishment execution method
def connect(self):
self.accept()
# Method to be executed when websocket is disconnected
def disconnect(self, close_code):
self.close()
# Execute the function when receiving a message from the websocket
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = f 'result:{text_data_json}'
self.send(text_data=json.dumps(
{
'message': message
}))
The code for the asynchronous method is as follows:
class ChatConsumer(AsyncWebsocketConsumer):
#Method to be executed when websocket connection is established
async def connect(self):
await self.accept()
# Methods to execute when websocket is disconnected
async def disconnect(self, close_code):
print(close_code)
# Execute the function when receiving a message from the websocket
async def receive(self, text_data):
for i in range (10 ):
time.sleep(i)
message = 'Result: ' + str(i)
await self.send(text_data=json.dumps({
'message': message
})
)
Note that all logic in asynchronous should be asynchronous, not a mix of synchronous and asynchronous code.
Fourth, the front-end Websocket use
WebSocket object supports four messages: onopen, onmessage, oncluse and onerror
onopen: when the browser and the websocket server connect successfully, the onopen message is triggered
onerror: The onerror message is triggered if the connection fails, or if there is a failure to send or receive data, or if there is a data processing error
onmessage: the onmessage message is triggered when the browser receives data from the websocket server, and the parameter e contains the data sent from the server
onclose: when the browser receives a request from the websocket server to close the connection, the onclose message is triggered
Splice the websocket request address to establish a long connection
var chatSocket = new WebSocket ('ws://' + window.location.host + '/ws/ver_update/');
Connection events
chatSocket.onopen = function () {
console.log(getCurrentDate (2 ) + ' ' + 'websocket connection success')
};
Error events
chatSocket.onerror = function () {
console. error (getCurrentDate ( 2) + ' ' + 'websocket connection error')
};
Close events
chatSocket.onclose = function (e) {
layer.msg ('websocket closed, checking error log', {icon: 2} );
console. error (getCurrentDate (2 ) + ' ' + 'websocket closed unexpectedly status code:' + e.code);
chatSocket.close();
};
Receiving events
chatSocket.onmessage = function ( e ) {
var data = JSON.parse(e.data);
}
V. Testing the Channels function
Summary: Since using the Websocket function, no more sudden front-end disconnections, for long-running tasks, the use of websocket is a good choice ~, there is a shortage of places please tell us more