Node.js和Socket.IO擴充Django的即時處理功能

來源:互聯網
上載者:User

Node.js和Socket.IO擴充Django的即時處理功能

   這篇文章主要介紹了使用Node.js和Socket.IO擴充Django的即時處理功能,用非同步處理即時功能是相當強大的,文中給出的例子是建立一個即時聊天室,需要的朋友可以參考下

  今天,我們的目標是使用Django,Redis,和Socket.IO建立一個即時的聊天室。雖然幾乎所有的Web應用程式都可以建立一個聊天室的。這篇文章將以較高的水平告訴你如何將基於REST的應用程式轉換成一個即時的Web應用程式的。我會使用Django建立REST的部分,實際上自由地使用任何你舒服的語言/架構均可。接下來,讓我們跳進代碼,先列舉我們所需要的部分。

  組成:

  Django 1.4+

  Redis 2.6.x (版本可選,但是建議使用)

  Redis-py 2.7.x (僅當你使用Redis時需要)

  Node.js v0.8.x

  Socket.IO v0.9.x

  Cookie v0.0.5

  資料庫、sqlite、其他你覺得類似資料庫形式的 均可

  你的使用的版本可能與我不同,我暫時未測試其他版本,全部使用當前最新穩定版本。如果你無法通過下面方法安裝,我已經編譯好Ubuntu的軟體包。你可以從評論中得到其他動作系統版本情況。

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#https://docs.djangoproject.com/en/dev/topics/install/

sudo apt-get install python-pip

sudo pip install django

 

#http://redis.io/download

sudo apt-get install redis-server

 

#https://github.com/andymccurdy/redis-py

sudo pip install redis

 

#https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager

sudo apt-get install python-software-properties

sudo add-apt-repository ppa:chris-lea/node.js

sudo apt-get update

sudo apt-get install nodejs

 

#https://github.com/LearnBoost/socket.io

npm install socket.io

 

#https://github.com/shtylman/node-cookie

npm install cookie

  讓我們從Django Project開始

  ?

1

2

3

django-admin.py startproject realtime_tutorial && cd realtime_tutorial

python manage.py startapp core

mkdir nodejs

  執行完以上的代碼,django project就配置好了,接下來要做的是在settings檔案中設定資料庫。先建立一個空白資料庫。(這是一個settings file的例子。在我的app中添加了一個“core”然後配置templates和urls的路徑。你可以隨意更改settings中的配置資訊,但是要與你的app相對應。

  Model

  models很簡單,我們將要建一個包含user和text的表。如果你想讓他更複雜一些,可以添加chatroom等資訊。(為了簡單起見,這裡唯寫了兩個)

  ?

1

2

3

4

5

6

from django.db import models

from django.contrib.auth.models import User

 

class Comments(models.Model):

user = models.ForeignKey(User)

text = models.CharField(max_length=255)

  這就是我們將要使用的model,接下來執行下面的syncdb代碼(第一行代碼),建立資料庫。然後建立幾個user來測試。(第二行代碼)

  ?

1

2

3

4

python manage.py syncdb

python manage.py createsuperuser

 

Node Server With Socket.IO

  這一部分將要介紹即時資訊的發送和擷取。使用Node.js建立一個依賴Socket.IO的app server,使用Redis 來做這項苦差事。在nodejs字典中,建立一個叫做“chat.js”的檔案,然後把它放在這裡:

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

var http = require('http');

var server = http.createServer().listen(4000);

var io = require('socket.io').listen(server);

var cookie_reader = require('cookie');

var querystring = require('querystring');

 

var redis = require('socket.io/node_modules/redis');

var sub = redis.createClient();

 

 

//訂閱chat channel

 

 

sub.subscribe('chat');

 

 

//配置socket.io來儲存Django設定的cookie

io.configure(function(){

io.set('authorization', function(data, accept){

if(data.headers.cookie){

data.cookie = cookie_reader.parse(data.headers.cookie);

return accept(null, true);

}

return accept('error', false);

});

io.set('log level', 1);

});

 

io.sockets.on('connection', function (socket) {

 

//把資訊從Redis發送到用戶端

sub.on('message', function(channel, message){

socket.send(message);

});

 

//用戶端通過socket.io發送訊息

socket.on('send_message', function (message) {

values = querystring.stringify({

comment: message,

sessionid: socket.handshake.cookie['sessionid'],

});

 

var options = {

host: 'localhost',

port: 3000,

path: '/node_api',

method: 'POST',

headers: {

'Content-Type': 'application/x-www-form-urlencoded',

'Content-Length': values.length

}

};

 

//使用Django server發訊息

var req = http.get(options, function(res){

res.setEncoding('utf8');

 

//輸出錯誤資訊

res.on('data', function(message){

if(message != 'Everything worked :)'){

console.log('Message: ' + message);

}

});

});

 

req.write(values);

req.end();

});

});

  首先,我們匯入並建立http server來監聽localhost 4000連接埠。然後訂閱Redis的 "chat" chanel。最後,只要我們在Django view中調用就可以了。

  上次我們設定了Socket.IO能在本地領域使用cookie的那個Django設定,這能讓我們通過socket.handshake.cookie去訪問cookie資料。能讓我們怎樣得到使用者的session會話。

  我們設定Socket.IO的cookies之後我們才能持有很多事件,第一個事件是Redis 發布通道,當我們的使用者注意到一個新的訊息已經被通知它將發送訊息給所有網站的用戶端。

  另一個事件是當用戶端通過Socket.IO發送一個資訊,我們使用字串查詢(queryString)模組去建立一個query查詢才能被發送到我們的Django服務。我們的Django服務在本地連接埠3000將會運行但你能改變了那個需求。路徑設定成/node_api那個URL我們將不久建立在Django旁邊。一旦我們發送queryString我們等待的Django就會儲存相關組件並給我們返回"Everything worked(都在工作)"。如果我們沒有得到返回給我們的輸出錯誤就關閉節點控制台

  一個關於不使用Redis的節點

  你真的完全沒必要為這項目使用Redis,我發現它將是一個好的學習體驗,如果你想分流Redis你可以建立一個通道,使用運算式或一些其它類庫,在這上面的代碼會從Django裡接收一個訊息當一個注釋被儲存時,然後你能通過Socket.IO添加註釋給所有的用戶端

  模板

  這就是我們所有HTML和javascript被放置的地方,它允許我們顯示注釋和互動我們的Node服務

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

<!DOCTYPE html>

<html>

<head>

<title>Realtime Django</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" type="text/javascript"></script>

<script src="http://localhost:4000/socket.io/socket.io.js"></script>

<script>

$(document).ready(function(){

var socket = io.connect('localhost', {port: 4000});

 

socket.on('connect', function(){

console.log("connect");

});

 

var entry_el = $('#comment');

 

socket.on('message', function(message) {

//Escape HTML characters

var data = message.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");

 

//Append message to the bottom of the list

$('#comments').append('<li>' + data + '</li>');

window.scrollBy(0, 10000000000);

entry_el.focus();

});

 

entry_el.keypress(function(event){

//When enter is pressed send input value to node server

if(event.keyCode != 13) return;

var msg = entry_el.attr('value');

if(msg){

socket.emit('send_message', msg, function(data){

console.log(data);

});

 

//Clear input value

entry_el.attr('value', '');

}

});

});

</script>

</head>

<body>

<ul id="comments">

{% for comment in comments %}

<li>{{comment.user}}: {{comment.text}}</li>

{% endfor %}

</ul>

<input type="text" id="comment" name="comment" />

</body>

</html>

  在上面我們用socket.IO在本地連接埠4000串連我們的節點服務。當從伺服器得到了一個資訊我們就在目錄和添加它到我們注釋列表裡做了些轉義,當我們想要發送一個資訊我們就對輸入盒子裡做了相應的13(按下一個鍵)的按鍵檢查。一旦那被按下後我們就發出資訊給伺服器使其被持有。一旦它被Django儲存到我們的資料庫我們就得到一個"message"事件將其添加到我們的會話列表裡

  我們的Django顯示我們在下一步將載入一個"comments"變數,因此我們那樣設定並遍曆下面所有的迴圈。這部分僅僅是當頁面初始載入時使用了,我們的javascript將添加資料給這個目錄作為一個新的資料來自我們的Node服務

  View

  開啟realtime_tutorial/core/views.py,然後像我一樣編輯:

  ?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

from core.models import Comments, User

 

from django.shortcuts import render

from django.http import HttpResponse, HttpResponseServerError

from django.views.decorators.csrf import csrf_exempt

from django.contrib.sessions.models import Session

from django.contrib.auth.decorators import login_required

 

import redis

 

@login_required

def home(request):

comments = Comments.objects.select_related().all()[0:100]

return render(request, 'index.html', locals())

 

@csrf_exempt

def node_api(request):

try:

#通過sessionid獲得 user

session = Session.objects.get(session_key=request.POST.get('sessionid'))

user_id = session.get_decoded().get('_auth_user_id')

user = User.objects.get(id=user_id)

 

#建立Comment

Comments.objects.create(user=user, text=request.POST.get('comment'))

 

#建立後就把它發送到聊天室

r = redis.StrictRedis(host='localhost', port=6379, db=0)

r.publish('chat', user.username + ': ' + request.POST.get('comment'))

 

return HttpResponse("Everything worked :)")

except Exception, e:

return HttpResponseServerError(str(e))

  讓我們看看這裡發生了什麼。home是一個標準的view檔案。使用select_related來獲得每一個comment的username,而不是在頁面第一次載入的時候,就返回一個comment的query集合。

  第二個就是我們Node app發送資訊的view。我們從POST中擷取sessionid,然後通過解碼獲得userid。確定user存在後,就可以建立comment了。現在吧username 和 comment 發送到 Redis server。最後,把資料發送到這裡叫做"chat"的頻道。

  URLs

  這裡比較簡單,因為我們將要使用Django內建的views和template。

  ?

1

2

3

4

5

6

7

8

from django.conf.urls import patterns, include, url

 

urlpatterns = patterns('',

url(r'^$', 'core.views.home', name='home'),

url(r'^node_api$', 'core.views.node_api', name='node_api'),

url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'admin/login.html'}, name='login'),

url(r'^logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}, name='logout'),

)

  Start It Up!

  開啟servers。

  ?

1

2

3

4

python manage.py runserver localhost:3000

 

#In a new terminal tab cd into the nodejs directory we created earlier

node chat.js

  我把代碼放到github。如果你想把它做得更好,就允許user建立、加入聊天室。你也可以使用PHP或者Rails開發。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.