In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-05 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
Node.js back-end framework design concept is what, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain in detail for you, people with this need can come to learn, I hope you can gain something.
The back-end core file mass.js contains functions such as batch creation and deletion of folders, MD5 encryption, type identification and module loading. Now the name of the site is still confused with the path of the site, and it will be independent into a configuration file in the future. As soon as you run the node mass.js command, you will immediately build a template website from the template file. Here is the main code for building the station:
/ /-start creating a website-/ / the name of the website you want to build (please correct here) mass.appname = "jslouvre"; / / under which directory to create the website (please correct here) mass.approot = process.cwd () / / method for path correction, you can pass N parameters mass.adjustPath = function () {[] .unshift.call (arguments,mass.approot, mass.appname); return require ("path") .join.apply (null,arguments)} var dir = mass.adjustPath (") / / mass.rmdirSync (dir); / /. Mass.require ("http,fs,path,scaffold,intercepters", function (http,fs,path,scaffold,intercepters) {mass.log ("=", true) if (path.existsSync (dir)) {mass.log ("this site already exists", true);} else {fs.mkdir (dir,0755) mass.log ("start using internal templates to build your website …" , true);} global.mapper = scaffold (dir); / / get the routing system http.createServer (function (req, res) {var arr = intercepters.concat () / / explanation of HTTP status http://www.cnblogs.com/rubylouvre/archive/2011/05/18/2049989.html req.on ("err500", function (err) {res.writeHead (500,{ "Content-Type": "text/html"}) Var html = fs.readFileSync (mass.adjustPath ("public/500.html")) var arr = [] for (var i in err) {arr.push ("" + I + ":" + err [I] + ")} res.write ((html+"). Replace ("{{url}}", arr.join (") Res.end (); req.on ("next_intercepter", function () {try {var next = arr.shift (); next & & next.apply (null,arguments)} catch (err) {req.emit ("err500", err) }}); req.emit ("next_intercepter", req, res);}) .console.log ("start server in 8888 port")})
As long as you run mass.js, it determines whether the site exists in the target path based on appname and approot, and creates a corresponding folder fs.mkdir (dir,0755). But more folders and files are done by scaffold.js. A list of folders in scaffold, which allows the program to copy the corresponding folder from templates to the path of the website, and create 505.html, 404.html, favicon.ico, routes.js and other files. The most important of these is routes, which is used to define routing rules.
/ / routes.js / / the most important part, generate controller, action, model, views mass.define ("routes", function () {return function (map) {/ / method route / / map.get ('/', 'site#index'); / / map.get (' / get_comments/:post_id','site#get_comments')) / / map.post ('/ add_comment','site#add_comment'); / / Resource routing / / map.resources ('posts'); / / map.resources (' users'); / / map.get ('/ view/:post_name','site#view_post') / / map.get ('/ rss','site#rss'); / / map.resources ('posts', {path:' articles', as: 'stories'}); / / nested routing / / map.resources (' posts', function (post) {/ / post.resources ('users')) / / Namespace routing map.namespace ("tests", function (tests) {tests.resources ('comments');}) / / map.resources (' users', {/ / only: ['index',' show'] / /}) / map.resources ('users', {/ / except: [' create', 'destroy'] / /}); / / map.resources (' users', function (user) {/ / user.get ('avatar',' users#avatar'); / /}) / / map.root ("home#index")}})
It's all about routes.js. Five types of routes are allowed to be established: root route, resource route, method route (get,delete,put,post), namespace route, and nested route. In fact, they are all reduced to resource routing, and each URL corresponds to a controller and its underlying action. It will call router.js, let the Router instance mapper in it call the contents of router.js, and then return mapper.
/ / scaffold.js var routes_url = mass.adjustPath ('config/routes.js'), action_url = "app/controllers/", view_url = "app/views/", mapper = new Router mass.require ("routes (" + routes_url+ ")", function (fn) {/ / read routes.js configuration file fn (mapper)}) / / leave it out here and explain return mapper later
After the Router instance mapper is running in routes, its several properties will add N multi-members and elements, and we will use it to further build our controller, view and model.
/ such as this.controllers = {}; now it becomes {comments: {actions: ['index',' create', 'new',' edit', 'destroy',' update', 'show'], views: [' index', 'new',' edit', 'show'], namespace:' tests'}} / / this.GET = [] Now it becomes [{controller: 'comments', action:' index', method: 'GET', namespace:' / tests/', url:'/ tests/comments.:format?', helper: 'tests_comments', matcher: / ^\ / tests\ / comments$/i}, {controller:' comments', action: 'new', method:' GET' Namespace:'/ tests/', url:'/ tests/comments/new.:format?', helper: 'new_tests_comments', matcher: / ^\ / tests\ / comments\ / new$/i}, {controller:' comments', action: 'edit', method:' GET', namespace: / tests/', url:'/ tests/comments/:id/edit.:format?' Helper: 'edit_tests_comment', matcher: / ^\ / tests\ / comments\ /\ d+\ / edit$/i}, {controller:' comments', action: 'show', method:' GET', namespace: / tests/', url:'/ tests/comments/:id.:format?', helper: 'tests_comment' Matcher: / ^\ / tests\ / comments\ /\ dashes I}]
Mapper has four array attributes, GET,POST,DELETE,PUT, which I call the matching stack. The elements of these arrays are all objects, and the objects all have a regular attribute of matcher, which is used to match the pathname attribute of the requested URL. Of course, first of all, we get its method and let the corresponding matching stack deal with it.
Now the scaffolding scaffold.js is still very simple, in the future it will be combined with hot deployment features, when users modify routes.js or other configuration files, it will automatically generate more views, controllers, and so on.
Then we start the server, and since req is an instance of EventEmitter, we can bind custom events to it at will. Here are two events, next_intercepter and err500. Needless to say, err500 is used to start the interceptor cluster. Here we just need to start *. It automatically starts the next one in the callback. These interceptors are uniformly loaded by intercepters.js.
/ / intercepters.js mass.intercepter = function (fn) {/ / interceptor shell return function (req, res, err) {if (err) {req.emit ("next_intercepter", req, res, err) } else if (fn (req,res) = true) {req.emit ("next_intercepter", req,res)}} var deps = ["mime", "postData", "query", "methodOverride", "json", "favicon", "matcher", "handle404"] / / "more", mass.define ("intercepters", deps.map (function (str) {return "intercepters/" + str}) .join (","), function () {console.log ("get a series of column interceptors"); return [] .slice.call (arguments,0)})
Each interceptor processes the original data and decides to continue to enable the next interceptor. For example, mime interceptor:
Mass.define ("intercepters/mime", function () {console.log ("this module is used to obtain MIME and exists as request.mime"); return mass.intercepter (function (req, res) {console.log ("enter MIME callback"); var str = req.headers ['content-type'] | |'; req.mime = str.split (';') [0]; return true })})
PostData interceptor
Mass.define ("intercepters/postData", "querystring", function (qs) {console.log ("this module is used to obtain the data requested by POST and exist as request.body"); return mass.intercepter (function (req,res) {console.log ("enter postData callback"); reqreq.body = req.body | | {} If (req._body | | / GET | HEAD/.test (req.method) | | 'application/x-www-form-urlencoded'! = = req.mime) {return true;} var buf =''; req.setEncoding ('utf8'); function buildBuffer (chunk) {buf + = chunk} req.on (' data', buildBuffer) Req.once ('end',function () {try {if (buf! = ") {req.body = qs.parse (buf); req._body = true } req.emit ("next_intercepter", req,res)} catch (err) {req.emit ("next_intercepter", req,res,err)} finally {req.removeListener ("data", buildBuffer)}});})
Query interceptor
Mass.define ("intercepters/query", "querystring,url", function (qs,URL) {console.log ("this module is used to get the parameters of URL and convert it to an object, which exists as request.query"); return mass.intercepter (function (req, res) {req.query = ~ req.url.indexOf ('?)? Qs.parse (URL.parse (req.url) .query): {}; return true;})})
MethodOverride interceptor
Mass.define ("intercepters/methodOverride", function () {console.log ("this module is used to correct method attributes"); var methods = {"PUT": "PUT", "DELETE": "DELETE"}, method = mass.configs.method | | "_ method"; return mass.intercepter (function (req, res) {reqreq.originalMethod = req.method) Var defaultMethod = req.method = = "HEAD"? "GET": req.method; var _ method = req.body? Req.body [method]: req.headers ['xmurhttpMeththafayoverride`] _ method = (_ method | | ") .toUpperCase (); req.method = methods [_ method] | | defaultMethod; if (req.body) {delete req.body [method];} return true;})})
Json interceptor
Mass.define ("intercepters/json", function () {console.log ("this module handles the JSON data sent from the front end"); return mass.intercepter (function (req, res, err) {reqreq.body = req.body | | {} If (req._body | | 'GET' = = req.method | |! ~ req.mime.indexOf ("json")) {console.log ("enter json callback") return true;} else {var buf ='; req.setEncoding ('utf8'); function buildBuffer (chunk) {buf + = chunk } req.on ('data', buildBuffer); req.once (' end', function () {try {req.body = JSON.parse (buf); req._body = true; req.emit ("next_intercepter", req,res) } catch (err) {err.status = 400; req.emit ("next_intercepter", req,res,err);} finally {req.removeListener ("data", buildBuffer);});}})})
Of all the interceptors, the most important is the matcher interceptor, which enters the portal to the framework's MVC system. Take out the pathname of the original request, then match it regularly, stop as long as one matches, then load the corresponding controller file, and call the corresponding action to process the request!
Mass.define ("intercepters/matcher", "url", function (URL) {console.log ("used to match the callback from the request") return mass.intercepter (function (req,res) {console.log ("enter matcher callback"); var pathname = URL.parse (req.url). Pathname, is404 = true,method = req.method, arr = mapper [method]; for (var I = 0, obj; obj = arr [callback +] ) {if (obj.matcher.test (pathname)) {is404 = false var url = mass.adjustPath ("app/controllers/", obj.namespace, obj.controller+ "_ controller.js") mass.require (obj.controller+ "_ controller (" + url + ")", function (object) {object [obj.action] (req,res)) / / enter the actionkeeper of the controller! Console.log (obj.action), function () {var err = new Error; err.statusCode = 404req.emit ("next_intercepter", req,res,err);}) break }} if (is404) {var err = new Error; err.statusCode = 404 req.emit ("next_intercepter", req,res,err);}})})
Behind the temple is the handle404 interceptor:
Mass.define ("intercepters/handle404", "fs,path", function (fs) {console.log ("this module is used to handle 404 errors"); return function (req, res, err) {console.log ("enter handle404 callback"); var accept = req.headers.accept | |'' If (~ accept.indexOf ('html')) {res.writeHead (404, {"Content-Type": "text/html"}); var html = fs.readFileSync (mass.adjustPath ("public/404.html")) res.write ((html+ ""). Replace ("{url}}", req.url)) Res.end ();} else if (~ accept.indexOf ('json')) {/ / json var error = {message: err.message, stack: err.stack}; for (var prop in err) error [prop] = err [prop] Var json = JSON.stringify ({error: error}); res.setHeader ('Content-Type',' application/json'); res.end (json) / / plain text} else {res.writeHead (res.statusCode, {'Content-Type':' text/plain'}); res.end (err.stack);})
Looking back at the controller section, the controller generated from the template is very simple:
Mass.define ("comments_controller", function () {return {"index": function () {}, "create": function () {}, "new": function () {}, "edit": function () {}, "destroy": function () {}, "update": function () {}, "show": function () {}}))
So you need to change it to be available, such as
"show": function (req,res) {res.writeHead (200,{ "Content-Type": "text/html"}); var html = fs.readFileSync (mass.adjustPath ("app/views/tests/show.html")) res.write (html); res.end ();}
It is later determined that the result of the action automatically invokes the view.
Of course, the framework is still very simple, it only took half a day. It must support ORM and static file caching. In addition, there is support such as cookie,session, which can be made into an interceptor.
The summary is as follows:
◆ determines whether a website exists, without using scaffolding to build a
◆ reads configuration files such as routes to generate controllers, views and models needed by the MVC system.
Through the hot deployment function, ◆ monitors users' changes to the configuration file and further intelligently generates controllers, views and models.
◆ is invited through a series of interceptors until the matcher interceptor enters the MVC system, where the model manipulates the database and renders the page. The application of interceptor cluster greatly improves the scalability of the application. There is no time to get the multithreading of node.js, maybe a lot of good things can be found in it.
Is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.