Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
简单的理解,Node.js 就是运行在服务端的 JavaScript。
我们可以通过 Node.js 实现服务端的开发,对于前端程序员来说,无论是从上手难易程度还是从性能角度,node 都是非常理想的选择。
安装 node 我们可以在下面的网址选择适合自己的版本下载。
Node 网址:
https://nodejs.org/en/
下载完成之后安装即可。
安装过程中只需要不断的点击下一步即可。
安装完成后,可以win+r
键输入 cmd,在命令提示窗口中输入node -v
出现版本号即表示安装成功。
NPM 是随同 node 一起安装的包管理工具,通过 NPM 我们可以非常方便的安装一些常用的包,以及解决 Node 部署等一些问题。
同时,我们也可以通过 NPM 将自己的包上传到 NPM 供别人使用。
因为 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);
原文:https://www.cnblogs.com/caominjie/p/11002277.html