本篇文章意在用node.js简单实现https://news.ycombinator.com 的部分后台功能,且nodejs的基本语法、html页面模板部分不再做描述。尚有不足,望指正,谢谢!<index><details><submit>一、原生js实现1、模块加载//加载需要的核心模块const http = require(‘http’);const url = require(‘url’);const path = require(‘path’);const fs = require(‘fs’);const querystring = require(‘querystring’);//加载需要的第三方模块,加载前需先在命令行通过npm下载,如npm i mime –saveconst mime = require(‘mime’);const template = require(‘art-template’);2、功能实现//创建服务器const server = http.createServer();//该全局常量存放数据加载地址(此例中用data.json存储数据,之后会写从mongoDB中获取数据)const data_path = path.join(__dirname, ‘./data.json’);//监听请求server.on(‘request’, (req, res) => { // ——–[首页模块]——— //设置路由 if (req.url == ‘/’ || req.url == ‘/index’) { //调用封装的从读取数据功能函数 readData(data_path, function (data) { let file_path = path.join(__dirname, ‘./views/index.html’); let obj = { list: data }; let html = template(file_path, obj); res.end(html); }); //——–以下注释部分代码为未封装读取数据功能前的代码(下文不再重复此部分代码)——— // 读取数据,将数据渲染到页面结构,再将结果响应给客户端 // fs.readFile(data_path, ‘utf8’, (err, data) => { // data = JSON.parse(data); // let file_path = path.join(__dirname, ‘./views/index.html’); // let obj = { list: data }; // let html = template(file_path, obj); // res.end(html); // }); } // ————-[详情页]————– else if (req.url.startsWith(’/details’)) { readData(data_path, function (data) { // 根据url中的id找到数据中的数据项,渲染到页面,将渲染结果响应给浏览器 let id = url.parse(req.url, true).query.id; let item = data.find((v, i) => { return v.id == id; }); let file_path = path.join(__dirname, ‘./views/details.html’); let html = template(file_path, item); res.end(html); }); } // ——————-[提交页:需针对不同请求方式进行处理]—————- else if (req.url == ‘/submit’) { fs.readFile(path.join(__dirname, ‘./views/submit.html’), (err, data) => { if (err) { return console.log(‘404 not found’); } res.end(data); }); } // 【若为get请求】提交后跳转到数据添加过渡页,需处理数据并重定向到首页 else if (req.url.startsWith(’/add’) && req.method == ‘GET’) { // 解析url,将查询数据转换为对象,并添加id属性 let item = url.parse(req.url, true).query; item.id = +new Date(); //确保id的唯一 // 获取json数据,将新对象追加到转为数组的数据中 readData(data_path, function (data) { data.unshift(item); //调用封装的将数据覆盖写入data.json的功能函数 writeData(data,function(){ // 重定向 res.statusCode = 302; res.setHeader(’location’, ‘/index’); res.end(); }); }); } // 【若为post请求】特别地,上传参数以数据流(二进制)的形式传输 else if (req.url.startsWith(’/add’) && req.method == ‘POST’) { // 监听查询数据上传,并将数据流拼接为字符串 let str = ‘’; req.on(‘data’, (chunk) => { str += chunk; }); // 监听到数据上传完成,将查询字符串解析为查询对象 req.on(’end’, () => { let item = querystring.parse(str); // 给此条对象添加id属性,并追加到数据中,再将数据重新覆盖写入本地 item.id = +new Date(); readData(data_path, function (data) { data.unshift(item); writeData(data,function(){ res.statusCode = 302; res.setHeader(’location’, ‘/index’); res.end(); }); }) }); } // ————[静态资源:可模拟apache,开放静态资源目录下的所有资源]———— else if (req.url.startsWith(’/assets’)) { let rs_path = path.join(__dirname, req.url); fs.readFile(path.join(__dirname, req.url), (err, data) => { if (err) { return console.log(‘404 not found’); } res.setHeader(‘content-type’, mime.getType(rs_path)); res.end(data); }); } // ———–非路由请求页面处理———– else { res.end(‘404’); }});3、功能函数封装// 功能:从data.json中读取数据并转换数据格式function readData(data_path, callback) { fs.readFile(data_path, ‘utf8’, (err, data) => { if (err) { return console.log(err); } data = JSON.parse(data); callback(data); });}// 功能:转换数据格式并将数据覆盖写入data.jsonfunction writeData(data, callback) { data = JSON.stringify(data, null, 2); fs.writeFile(data_path, data, (err) => { if (err) { return console.log(err); } // 若写入成功则执行回调 callback(); });}// 开启服务器server.listen(8001, () => { console.log(‘server is started ,pls visit http://localhost:8001’);})未完待续: 1、模拟express封装渲染和重定向功能(使之为request对象的成员); 2、模块化; 3、express实现