Use angular and nodejs to build chat rooms

Source: Internet
Author: User
Tags emit readfile

One, using node to build a static server

This is the bottom support part of the project. Used to support static resource files like HTML, CSS, GIF, JPG, PNG, JavaScript, JSON, plain text, etc. static resource access. There is a file map with a MIME type in it.

Mime.js

/** * MIME type map * @ author      Cheng Liufeng * @ Date        2014/8/30 * When requesting static server file type HTML, CSS, GIF, JPG, PNG, JavaScript , JSON, plain text, we will map this file */exports.types = {  "css": "Text/css",  "gif": "Image/gif", "  html": "text/ HTML ",  " ico ":" Image/x-icon ",  " JPEG ":" Image/jpeg ",  " jpg ":" Image/jpeg ",  " JS ":" Text/javascript ",  "JSON": "Application/json",  "PDF": "Application/pdf",  "png": "Image/png",  "svg": "image/svg+ XML ",  " swf ":" Application/x-shockwave-flash ",  " TIFF ":" Image/tiff ",  " TXT ":" Text/plain ",  " wav ":" Audio/x-wav ",  " wma ":" Audio/x-ms-wma ",  " wmv ":" Video/x-ms-wmv ",  " xml ":" Text/xml "};

  I'll explain the process of appearing from the input URL to the page. When the user enters a URL in the browser address bar. A series of processes will take place next. The first is DNS resolution, the domain name is converted to the corresponding IP address, then the browser and the remote Web server through the TCP three handshake negotiation to establish a TCP/IP connection. The handshake consists of a synchronous message, a synchronous-response message, and a response message, which is passed between the browser and the server in three messages. The handshake is first attempted by the client to establish communication, then the server answers and accepts the client's request, and finally the client sends a message that the request has been accepted. Once a TCP/IP connection is established, the browser sends a GET request for HTTP to the remote server through the connection. The remote server locates the resource and returns the resource using an HTTP response, and the HTTP response status of 200 indicates a correct response. At this point, the Web server provides the resource service and the client begins to download the resource. The downloaded resources include HTML files, CSS files, javascript files, image files. then start building a render tree and a DOM tree, with CSS blocking and JS blocking. So the bottom layer is the need for a static server support. I was born in this. Constructs a static server, does not adopt the express frame.

In fact, the process of each resource file request is a GET request again and again. Let me explain the service-side process for the client (either the browser side or the GET request with Curl under Linux). Once a GET request is sent to the server, the server can correspond to a path to a resource file based on the GET request. Knowing this path, we can take the file read and write to get the resources under the specified path, and then return to the client.

We know that the file read and write API in node is ReadFile and Readfilesync, but the better way is to use the stream to read the file, the advantage of the flow is that the cache and gzip compression can be used.

OK, so how do you implement caching? Typically, when the client first requests a request, the server reads the resource file and returns it to the client. But the second time to request the same file, this time still need to send a request to the server. The server will determine if the resource has been cached based on HTTP header information such as expires, Cache-control, if-modified-since, etc. If there is a cache, the server does not access the actual path of the resource file again. Returns the cached resource directly.

Server.js

/** * Chat Room Server * Features: Implementation of node version of the static servers * implemented cache, gzip compression, etc. * @ author Cheng Liufeng * @ Date 2014/8/30 *//Set the port number var PO  RT = 3000;//Introduces module var http = require (' http '), var url = require (' URL '); var fs = require (' FS '); var path = require (' path '); var Zlib = require (' zlib ');//introduce file var mime = require ('./mime '). Types;var config = require ('./config '); var chatserver = Requir E ('./utils/chat_server '); var server = Http.createserver (function (req, res) {Res.setheader ("server", "NODE/V8");// Get file path var pathName = Url.parse (Req.url). Pathname;if (Pathname.slice ( -1) = = = "/") {PathName = PathName + "index.html"   ; The default is to take the current default index.html}//security (when accessed using the Linux Curl command, there is a security risk) var Realpath = Path.join ("Client", Path.normalize (PathName. Replace (/\.\./g, "")));//Check the file path exists path.exists (Realpath, function (exists) {///When the file does not exist, output a 404 error if (!exists) { Res.writehead (404, "Not Found", {' Content-type ': ' Text/plain '}); Res.write ("The request URL" + PathName + "was not found!") ; Res.end ();}                   else {   Processing logic when a file exists Fs.stat (Realpath, function (err, stat) {//Get file extension var ext = PA                Th.extname (Realpath); Ext = ext?                Ext.slice (1): "Unknown"; var contentType = Mime[ext] | |                "Text/plain"; Set Content-type res.setheader ("Content-type", ContentType); var lastmodified = stat.mtime.toUTCString (); v Ar ifmodifiedsince = "if-modified-since". toLowerCase (); Res.setheader ("last-modified", lastmodified); If (Ext.match ( Config.                    Expires.filematch) {var Expires = new Date (); Expires.settime (expires.gettime () + CONFIG.                    Expires.maxage * 1000);                    Res.setheader ("Expires", expires.toutcstring ()); Res.setheader ("Cache-control", "max-age=" + CONFIG.)                Expires.maxage);                    } if (Req.headers[ifmodifiedsince] && lastmodified = = Req.headers[ifmodifiedsince]) { Res.writehead (304, "not Modified");                Res.end ();                } else {//use stream to read file var raw = Fs.createreadstream (Realpath); var acceptencoding = req.headers[' accept-encoding ' | |                "";                var matched = Ext.match (Config.Compress.match); if (matched && acceptencoding.match (/\bgzip\b/)) {Res.writehead ($, "OK", {' Content-encod                        ing ': ' gzip '});                    Raw.pipe (Zlib.creategzip ()). pipe (RES); } else if (matched && acceptencoding.match (/\bdeflate\b/)) {Res.writehead ($, "OK", {' Con                        Tent-encoding ': ' deflate '});                    Raw.pipe (Zlib.createdeflate ()). pipe (RES);                        } else {res.writehead ("OK");                    Raw.pipe (RES); }//below is the normal way to read the file, not recommended//Fs.readfile (Realpath, "binary", function (err, data) {//if (err) {////file exists, b UT has some ERRor while Read//res.writehead ($ {' Content-type ': ' Text/plain '});//res.end (err);/} else {////file exists, can                Success Return//res.writehead ($, {' Content-type ': ContentType});//res.write (data, "binary");//res.end ();//}//}); }});}});});/ /Listen for 3000 port server.listen (port, function () {Console.log ("Server is listening on port" + Port + "!");}); /Let the Socket.io server and the HTTP server share a port chatserver.listen (server);

  Second, the server uses WebSocket to build the chat room service side

Why use WebSocket?

We know that the mainstream chat room is still using AJAX to achieve client and server communication. The use of a polling mechanism. The so-called polling, is the client every once in a while to send a request, ask the server, see if there is no new chat data server, if there is new data, return to the client.

WebSocket is completely different. WebSocket is based on long links. Is that the link will persist once the link is established between the client and the server. is a full-duplex communication. This time the mechanism is somewhat similar to the publish-subscribe pattern. The client subscribes to events that are proactively pushed to the client when new data appears on the server.

WebSocket is using the WS-Protocol, not the HTTP protocol or the HTTPS protocol. Another advantage of using websocket is that it can reduce a lot of data traffic. At the beginning of the article, I have introduced a traditional resource request process that requires three handshake protocols, and each request header occupies a larger space, which can be very cost-per-flow. And the websocket inside the communication header is very small-about 2 Bytes.

/** * Chat Service. */varSocketio = require (' Socket.io '));vario;varGuestnumber = 1;//Initial user name numbervarnicknames = {};//Nickname Listvarnamesused = [];//user names that have been usedvarCurrentroom = {};//Current chat room
functionassignguestname (socket, Guestnumber, nicknames, namesused) {varname = ' Guest ' +Guestnumber; Nicknames[socket.id]=name; Socket.emit (' Nameresult ', {success:true, name:name}); Namesused.push (name); returnGuestnumber + 1;}functionJoinroom (socket, guest) {Socket.join (guest); Currentroom[socket.id]=the hostel ; Socket.emit (' Joinresult ', {room:room}); Socket.broadcast.to (Guest). Emit (' Message ', {text:nicknames[socket.id]+ ' has joined ' + + + '. ' });}functionhandlemessagebroadcasting (socket) {Socket.on (' Message ',function(message) {socket.broadcast.to (message.room). Emit (' Message ', {text:nicknames[socket.id]+ ': ' +Message.Text}); });} Exports.listen=function(server) {IO=Socketio.listen (server); Io.set (' Log level ', 1); //define connection handling for each userIo.sockets.on (' Connection ',function(socket) {//Assigning a user nameGuestnumber =assignguestname (socket, Guestnumber, nicknames, namesused); //Add user to chat room lobbyJoinroom (socket, ' Lobby '); //Handling Chat Messageshandlemessagebroadcasting (socket, nicknames); //handlenamechangeattempts (socket, nicknames, namesused); //handleroomjoining (socket); //handleclientdisconnection (socket, nicknames, namesused); });};

Third, use angular to build chat room client

Why use angular?

As a front-end MVC framework, angular.js is undoubtedly compelling. Modular, bidirectional data binding, instruction system, dependency injection. and angular built-in jquerylite, which makes it easy for students who are familiar with jquery syntax.

Of course, personally, angular has a great advantage in building a single-page application and CRUD project. Our chat room is based on the purpose of the SPA (single page application).

Index.html

<!DOCTYPE HTML><HTMLNg-app= "Chatapp"><Head>    <Metaname= "Viewport"content= "Width=device-width, User-scalable=no"></Head><BodyNg-controller= "Initctrl">    <DivNg-view></Div>    <Scriptsrc= "Lib/angular.js"></Script>    <Scriptsrc= "Lib/angular-route.js"></Script>    <Scriptsrc= "Lib/socket.io.js"></Script>    <Scriptsrc= "App.js"></Script>    <Scriptsrc= "Controllers/initctrl.js"></Script></Body></HTML>

How do I build a single page application? How does a single page application work?

Let's talk about the principle of single page application. The so-called single page, not the entire page no refresh. When you review the console console of Google Chrome, you'll find that Ajax is used internally by angular to request resources asynchronously. So just a partial refresh. However, this approach has made a lot of progress relative to the deletion and modification of the previous DOM nodes.

To build a single page application, we need to use angular-route.js. This angular sub-project can help us define the route and the corresponding logical processing controller. With it, we can implement a single page application.

App.js

 /*  * * Client (currently only supported browser, future extension to mobile) program entry file * Create a module and name Chatapp * To configure the route for single page application  */ var  Chatapp = Angular.module ("Chatapp", [' Ngroute '  ' view     S/init.html '  ' Initctrl ' }) . When ( '/init '  ' views/init.html ' }); });

  

The code logic for the client chat interface is as follows

Initctrl.js

/** * # Initctrl*/Angular.module (' Chatapp '). Controller (' Initctrl ',function($scope) {varSocket = Io.connect (' http://127.0.0.1:3000 '); Socket.on (' Nameresult ',function(Result) {varmessage; if(result.success) {message= ' You're now known as ' + Result.name + '. '; Console.log (' Message= ', message); document.getElementById (' Guestname '). InnerHTML =message; } Else{message=Result.message;    }    }); Socket.on (' Joinresult ',function(Result) {document.getElementById (' Guest '). InnerHTML =Result.room;    }); $scope. SendMessage=function() {        varMessage ={:' Lobby ', Text:document.getElementById (' User_input '). Value}; Socket.emit (' Message ', message);    }; Socket.on (' Message ',function(message) {varp = document.createelement (' P '); P.innerhtml=Message.Text; document.getElementById (' Message '). appendchild (P); });});

Need to download the source code can access this address: https://github.com/Geek-Coder/Geek-Coder-Chat 

Use angular and nodejs to build chat rooms

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.