Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。html
简单的理解,Node.js 就是运行在服务端的 JavaScript。前端
咱们能够经过 Node.js 实现服务端的开发,对于前端程序员来讲,不管是从上手难易程度仍是从性能角度,node 都是很是理想的选择。node
安装 node 咱们能够在下面的网址选择适合本身的版本下载。程序员
Node 网址:npm
https://nodejs.org/en/
下载完成以后安装便可。数组
安装过程当中只须要不断的点击下一步便可。缓存
安装完成后,能够win+r
键输入 cmd,在命令提示窗口中输入node -v
出现版本号即表示安装成功。服务器
NPM 是随同 node 一块儿安装的包管理工具,经过 NPM 咱们能够很是方便的安装一些经常使用的包,以及解决 Node 部署等一些问题。架构
同时,咱们也能够经过 NPM 将本身的包上传到 NPM 供别人使用。app
由于 NPM 是随着 Node 一切安装的工具,因此只要 Node 安装成功,那么咱们就能够直接使用 npm。
经过下面的命令能够查看 NPM 的版本。
npm -v
由于 NPM 的服务器架设在国外,因此当咱们安装一些包的时候不免会产生速度上的问题致使下载失败,因此不少时候咱们须要切换下载的服务器,咱们将之称为源
。而 nrm 就是用来帮我咱们切换下载源的一个工具。
首先先来经过 npm 安装 nrm。
npm install -g nrm install:安装 -g 全局安装 若是不加-g表示只安装在当前的目录 nrm 包名
经常使用源
通常在国内从事 node 开发,常用的源以下:
当咱们安装完 nrm 以后,能够经过nrm ls
来查看可选的源。
* npm ---- https://registry.npmjs.org/ cnpm --- http://r.cnpmjs.org/ taobao - https://registry.npm.taobao.org/ nj ----- https://registry.nodejitsu.com/ npmMirror https://skimdb.npmjs.com/registry/ edunpm - http://registry.enpmjs.org/
带有* 的源地址表示是当前正在使用的源
切换源
能够经过下面的这条命令切换源:
nrm use 源名
例如,想要使用淘宝的源,能够采用以下的命令:
nrm use taobao
测试速度
咱们能够经过nrm test
测试相应源的响应时间。
例如,想要测试官方源的响应时间,能够采用以下的写法:
nrm test npm
咱们也能够测试全部源的速度。
nrm test
咱们在开发 node 项目的时候,每一次代码的更改,都须要从新启动一次 node 服务器,相对来讲对咱们的开发并非很方便,因此咱们能够选择使用nodemon
工具,能够很好的帮助咱们调试代码。
安装方式:
npm install -g nodemon
启动应用
当咱们须要启动应用的时候,以前是经过:
node appName
若是要使用 nodemon 的话,则能够改成以下:
nodemon appName
查看帮助文档
若是想要查看内置的帮助文档,能够经过以下:
nodemon -h 或者 nodemon --help
设置端口
若是没有在代码中设置端口,那么能够经过下面的命令在运行的时候设置端口:
nodemon ./server.js localhost 8080
开启 debug 模式
若是想要开启 debug 模式,能够经过以下的命令:
nodemon --debug ./server.js 80
在 node.js 中,应用由模块组成,采用 CommonJS 模块规范。
简单点说,每个文件就是一个模块,拥有属于本身的做用域。在每个模块当中定义的变量、函数、类都是私有的,也就是说对其余的文件不可见。
例如,在 a.js 中,存在一个变量 x 的内容是hello,world
。此时,变量 x 至关于在 a.js 中的私有变量。只可以在 a 中使用。
可是在 b.js 中,若是想要使用 a.js 中的变量 x,那么能够采用以下的写法:
let x = "hello,world"; module.exports.x = x; // 至关于将这个变量输出
在 b.js 中使用以下:
let info = require("./a.js"); console.log(info.x); //hello,world
CommonJS 模块的特色以下:
* 全部代码都运行在模块做用域,不会污染全局做用域。 * 模块能够屡次加载,可是只会在第一次加载时运行一次,而后运行结果就被缓存了,之后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。 * 模块加载的顺序,按照其在代码中出现的顺序。
经过http
模块,咱们能够快速的建立一个服务器,用于开发和测试。
const http = require("http"); // 建立一个服务 let server = http.createServer((req,res)=>{ res.write("hello,Node!"); res.end(); }); // 监听端口 server.listen(8080);
在上面的代码中,咱们首先经过require
引入了http模块。
其次经过createServer
方法建立了一个服务,而且经过listen
方法监听了8080
端口。
在上面的代码中,res.write()
方法和res.end()
方法是两个很是重要的方法,write
表示向客户端输入内容,而end
方法则告诉客户端,响应结束。
在createServer
方法中,须要一个回调函数,这个回调函数中须要设置两个形参,一个是req
,表示request
,另一个是res
,表示response
,两个形参分别对应着请求和响应。
咱们能够经过req
获取更多的关于请求的内容。
例如能够经过req.url
获取用户请求的地址以及get请求传递的参数。
const http = require("http"); // 建立一个服务 let server = http.createServer((req,res)=>{ res.write(req.url); res.end(); }); // 监听端口 server.listen(8080);
例如上面的代码,当用户输入的地址为localhost:8080/index.html
的时候,在网页当中就会输出/index.html
。
咱们若是想要经过url获取用户的更多的信息,可使用url
模块。
const url =require("url");
在url
对象当中,咱们可使用parse()
方法来解析url信息。
const http = require("http"); const url = require("url"); // 建立一个服务 let server = http.createServer((req,res)=>{ console.log(url.parse(req.url)); // 获取url路径信息 res.write(req.url); res.end(); }); // 监听端口 server.listen(8080);
上面的代码经过url对象的parse方法打印出了url的信息以下:
Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: null, query: null, pathname: '/index.html', path: '/index.html', href: '/index.html' }
若是咱们在其中还传入了一些其余的参数,那么相同的代码打印结果可能与下面的内容相似:
Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: '?username=zhangsan', query: 'username=zhangsan', pathname: '/index.html', path: '/index.html?username=zhangsan', href: '/index.html?username=zhangsan' }
若是咱们想要得到其中的参数,能够直接采用以下的代码:
let req_info = url.parse(req.url); console.log(req_info.query);// 输出信息相似于 username=zhangsan&age=30
若是想要对数据进行必定的处理,能够采起相似以下的代码:
const http=require('http'); const querystring=require('querystring'); let server=http.createServer(function (req, res){ let [url, query]=req.url.split('?'); let get=querystring.parse(query); console.log(url, get); res.end(); }); server.listen(8080);
在上面的代码中,咱们为了更加细致的处理url,引入了querystring
模块。
const querystring=require('querystring');
首先咱们经过split
方法将地址和参数以?
为分界切割开。而且将结果解构赋值给url和query两个变量。
let [url, query]=req.url.split('?');
若是咱们须要进一步解析数据,咱们能够经过querystring
里面的parse()
方法,直接解析query
。
let get=querystring.parse(query);
若是客户端发送的是post请求,那么处理方式能够以下:
// server.js const http = require("http"); const querystring = require("querystring"); let server = http.createServer((req,res)=>{ let arr = []; req.on('data',buffer=>{ arr.push(buffer); // 将buffer数据存入到数组当中 }) req.on("end",()=>{ let buffer = Buffer.concat(arr); // 缓冲区合并 let post=querystring.parse(buffer); res.write(buffer); //将内容输出网页当中去 res.end(); }) }) server.listen(8080)
在上面的代码中,咱们经过req
中的on
方法来处理用户经过post方法传递过来的数据,而且随着数据的传递将数据以buffer的形式存入到数组当中。
let arr = []; req.on('data',buffer=>{ arr.push(buffer); // 将buffer数据存入到数组当中 })
紧接着,当数据传递结束后,经过Buffer.concat()
方法来将缓冲区的buffer数据合并。
req.on("end",()=>{ let buffer = Buffer.concat(arr); // 缓冲区合并 let post=querystring.parse(buffer); res.write(buffer); //将内容输出网页当中去 res.end(); })
须要注意的是,buffer
数据是一组二进制的数据的数据,虽然咱们不认识,可是电脑认识,因此咱们无需处理,直接输入到网页中便可。若是想要看其内容,能够在其后面使用toString
方法。
咱们能够经过fs
模块来实现文件的读取工做。
const fs = require("fs");
在fs
模块当中有四个经常使用的方法,以下:
fs.writeFile() 异步写入文件 fs.writeFileSync() 同步写入文件 fs.readFile() 异步读取文件 fs.readFileSync() 同步读取文件
上面的四个方法,咱们较为经常使用的是两个异步的方法,由于不管是从速度仍是从性能的角度考虑,异步都要好于同步。
其中,两个异步方法须要的参数以下:
fs.readFile(path,callback) ;// 路径和回调函数 fs.writeFile(path,data,callback);// 路径 数据 回调函数
例如,咱们想要读取一个文件,能够以下:
const fs = require("fs"); fs.readFile('./aa.txt',(err,data)=>{ if(err){ console.log('失败,'+err); }else { console.log(data.toString()); // hello,world } })
上面的代码中,经过在readFile
中传入第一个参数须要读取的文件路径
,第二个参数callback
。
fs.readFile('./aa.txt',(err,data)=>{}
其中,若是读取文件失败,那么就提示错误信息。若是想要查看读取的内容,能够在获得的数据后面使用toString()
方法。
if(err){ console.log('失败,'+err); }else { console.log(data.toString()); // hello,world }
下面是经过writeFile()
方法写入内容:
fs.writeFile("bb.txt","hi,this file is bb.txt",err=>{ if(err){ console.log("失败:" + err); }else { console.log("成功"); } })
上面的代码中,在调用writeFile()
时,传入的第一个参数是写入的文件路径和文件名
,第二个参数是要写入的数据,第三个参数则是一个回调函数,在回调函数中存在一个形参err
,当写入出错时就会传入参数,经过err
这个形参就能够获取错误信息。
当用户在客户端请求一个文件的时候,咱们能够经过服务端进行判断,而且经过readFile()
方法读取指定位置的文件。
const http = require("http"); const fs = require("fs"); let server = http.createServer((req,res)=>{ if (req.url === "/a.png"){ fs.readFile("./a.png",(err,data)=>{ if(err){ res.write("请求失败:" + err); }else { res.write(data); } res.end(); }) } }); server.listen(8080);
在上面的代码中,咱们首先建立了服务器。
http.createServer((req,res)=>{})
咱们经过req.url
来判断客户端请求的路径,若是用户请求的是a.png
,那么就去读取本地的文件。
if(req.url === "/a.png"){ fs.readFile("./a.png",(err,data)=>{ }) }
在回调函数中,若是请求出错,就返回err
错误信息,若是没有请求出错,那么就直接输出数据信息。
if(err){ res.write("请求失败:" + err); }else { res.write(data); } res.end();
咱们若是想要判断客户端请求的方法,那么能够经过method
来进行判断。
let server = http.createServer((req,res)=>{ if(req.method === "GET"){ console.log("请求方法为get.."); }else if(req.method === "POST"){ console.log("请求方法为POST..."); } });
上面代码中,若是客户端发送的请求为get请求,那么就是输出请求方法为get
,若是发送的请求为post,那么就是输出请求方法为post
。
下面咱们来简单的作一个路由配置。
须要注意的是,实际的项目开发当中,路由每每都是经过框架构建而成。
// 路由配置 const http = require('http'); const url = require('url'); const querystring = require('querystring'); const fs = require('fs'); let users={}; // 先来建立一个简单的服务器 let server = http.createServer((req, res) => { // 建立几个变量用来存储位置信息 let path = '', get = {}, post = {}; if (req.method === "GET") { let { pathname, query } = url.parse(req.url, true); path = pathname; get = query; complete(); } else if (req.method == 'POST') { path = req.url; let arr = []; req.on('data', buffer => { arr.push(buffer); }); req.on('end', () => { let buffer = Buffer.concat(arr); post = querystring.parse(buffer.toString()); complete(); }); } function complete() { if (path == '/reg') { let { username, password } = get; if (users[username]) { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 1, msg: '此用户名已存在' })); res.end(); } else { users[username] = password; res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 0, msg: '' })); res.end(); } } else if (path == '/login') { let { username, password } = get; if (!users[username]) { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 1, msg: '找不到此用户' })); res.end(); } else if (users[username] != password) { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 1, msg: '密码不对' })); res.end(); } else { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 0, msg: '' })); res.end(); } } else { fs.readFile(`www${path}`, (err, buffer) => { if (err) { res.writeHeader(404); res.write('Not Found'); res.end(); } else { res.write(buffer); res.end(); } }); } } }); server.listen(8080);