node基本使用

879 阅读9分钟

1. Node.js是什么

  • Node.js不是一门语言不是库不是框架
  • Node.js是javascript运行时环境。简单来说就是Node.js可以解析和执行js代码,现在js可以脱离浏览器运行
  • 浏览器中的js
    1. Ecmascript(基本语法,if,var,function)
    2. DOM
    3. BOM
  • Node 中的 JavaScript
    1. 没有DOM BOM(不能识别window和document)
    2. EcmaScript
    3. Node.js不操作页面,为js提供一些服务器端的操作:文件的读写,网络服务的搭建,网络通信等
  • event-driven事件驱动、非阻塞i/o模型、轻量高效

2. Node.js使用

2.1 文件的操作

终端用node 文件名开打开文件

fs 是 file-system 的简写,就是文件系统的意思,在 Node 中如果想要进行文件操作,就必须引入 fs 这个核心模块 var fs = require('fs')

  • 读文件fs.readFile
fs.readFile('./data/a.txt', function (error, data) {
//第一个参数就是要读取的文件路径
// 第二个参数是一个回调函数
	if(error){
		console.log('有错误')
	}else{
		console.log(data.toString())
	}
}

成功——data 数据,error undefined没有数据 失败—— data undefined没有数据,

  • 写文件 fs.writeFile(文件路径,写入的内容,回调函数)
  • 读取文件夹的目录 fs.readdir()

2.2 服务器的操作

  • 创建一个 Web 服务器
// 1. 加载 http 核心模块
var http = require('http')
// 2. 使用 http.createServer() 方法创建一个 Web 服务器,返回一个 Server 实例
var server = http.createServer()
// 3.当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
server.on('request', function () {
  console.log('收到客户端的请求了')
})
// 4. 绑定端口号,启动服务器
server.listen(3000, function () {
  console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
  • request 请求事件处理函数
server.on('request', function (request, response) {
  console.log('收到客户端的请求了,请求路径是:' + request.url)
//request.url是     http://127.0.0.1:3000/  后边的东西

  // response 对象有一个方法:write 可以用来给客户端发送响应数据
  // write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待
  response.write('hello')
  response.write(' nodejs')

  // 告诉客户端,我的话说完了,你可以呈递给用户了
  response.end()

 
})

可以直接一句话 response.end('hello nodejs')。响应内容只能是二进制或字符串

http.createServer(function(request,response){
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
}).listen(888);

  • 页面重定向
    • 状态码设置为 302 临时重定向(301永久重定向) response.statusCode = 302
    • 在响应头中通过 Location 告诉客户端往哪儿重定向 response.setHeader('Location', '/')

2.3 核心模块

文件操作的fs模块、http服务构建的http模块、path路径操作模块、os操作系统信息模块等等。使用模块就要先引入
var fs =  require('fs)
var http = require('http')

2.4 require

require 是一个方法,它的作用就是用来加载模块的。在 Node 中,模块有两种:
  • 具名的核心模块,例如 fs、http(fs是动态读取文件信息)
  • 用户自己编写的文件模块 相对路径必须加 ./ 可以省略后缀名 相对路径中的 ./ 不能省略,否则报错

注意:

  • 在 Node 中,没有全局作用域,只有模块作用域
  • 外部访问不到内部, 内部也访问不到外部。默认都是封闭的
  • 有时候,我们加载文件模块的目的不是为了简简单单的执行里面的代码,更重要是为了使用里面的某个成员

2.5 http

  • 端口号

    • ip 地址定位计算机
    • 端口号定位具体的应用程序
    • 端口号的范围是0-65536之间,一些计算机默认的端口号例如80 最好不要使用
  • Content-Type

    • 服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
    • 不同的资源对应的 Content-Type 是不一样,具体参照:tool.oschina.net/commons
    • 对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
    • res.setHeader('Content-Type', 'text/plain; charset=utf-8')——普通文本
    • res.setHeader('Content-Type', 'text/html; charset=utf-8') ——html 格式的字符串
  • 通过网络发送文件

    • 发送的并不是文件,本质上来讲发送是文件的内容
    • 当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理

2.6 apache目录文件

得到某目录下的文件名和目录名 fs.readdir
  • 获取文件目录
  • 将得到的文件名和目录名替换到 template.html 中data = data.replace('^_^', content)
  • 发送解析替换过后的响应数据res.end(data)
  • 打开服务器就可以获取到想要得到的文件名和文件目录

2.7 模板引擎art-template

可以在浏览器中使用也可以在node中使用
  • 在浏览器中使用
    • 首先安装npm install art-template
    • 在浏览器中需要引用 lib/template-web.js 文件
    • 模板引擎不关心你的字符串内容,只关心自己能认识的模板标记语法,例如 {{}}
 <script type="text/template" id="tpl">
     {{ name }}
  </script>
  <script>
	var ret = template('tel',{
		name:'jack'
	})
  </script>
  //模板的循环
  {{each 数组]}
 	{{$value}}
  {{/each}}
  • 在node中使用
    • 在需要使用的文件模块中加载 art-templaterequire('art-template')
    • 使用render渲染
 var ret = template.render(data.toString(), {
    name: 'Jack',
  })

  • 服务端渲染和客户端渲染的区别 (服务端渲染就是在服务端使用模板引擎)
    • 客户端渲染不利于 SEO 搜索引擎优化
    • 服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的
    • 所以你会发现真正的网站既不是纯异步也不是纯服务端渲染出来的
    • 而是两者结合来做的
    • 例如京东的商品列表就采用的是服务端渲染,目的了为了 SEO 搜索引擎优化
    • 而它的商品评论列表为了用户体验,而且也不需要 SEO 优化,所以采用是客户端渲染

2.8 路由模块

var url = require('url')
var obj = url.parse('/pinglun?name=的撒的撒&message=的撒的撒的撒', true)

参数为true的时候可以获取到后面的search值,并将其转为对象格式

   query:  { name: '的撒的撒', message: '的撒的撒的撒' }

2.9 path路径操作模块

  • path.basename 获取一个路径的文件名(默认包含扩展名)
  • path.dirname 获取一个路径中的目录部分
  • path.parse 把一个路径转为对象
    • root根路径
    • dir目录
    • base包含后缀名的文件名
    • ext后缀名
    • name不包含后缀名的文件名
  • path.join 进行路径的拼接
  • path.isAbsolute判断一个路径是不是绝对路径

补充:

path.resolve('/foo/bar', './baz')    // '/foo/bar/baz' 
path.resolve('/foo/bar', '/tmp/file/')   //  '/tmp/file' 

path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif') 
// 当前的工作路径是 /home/itbilu/node,则输出结果为 
'/home/itbilu/node/wwwroot/static_files/gif/image.gif'
const path = require('path'); 
let myPath = path.join(__dirname,'/img/so'); 
let myPath2 = path.join(__dirname,'./img/so'); 
let myPath3 = path.resolve(__dirname,'/img/so'); 
let myPath4 = path.resolve(__dirname,'./img/so'); 
console.log(__dirname); //D:\myProgram\test 
console.log(myPath); //D:\myProgram\test\img\so 
console.log(myPath2); //D:\myProgram\test\img\so 
console.log(myPath3); //D:\img\so<br> 
console.log(myPath4); //D:\myProgram\test\img\so

2.10 导出成员exports 和 module.exports

  • 每个模块中都有一个 module 对象
  • module 对象中有一个 exports 对象
  • 我们可以把需要导出的成员都挂载到 module.exports 接口对象中
  • 也就是:moudle.exports.xxx = xxx 的方式
  • 但是每次都 moudle.exports.xxx = xxx 很麻烦,点儿的太多了
  • 所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:exports
  • exports === module.exports 结果为 true
  • 所以对于:moudle.exports.xxx = xxx 的方式 完全可以:expots.xxx = xxx
  • 当一个模块需要导出单个成员的时候,这个时候必须使用:module.exports = xxx 的方式
  • 不要使用 exports = xxx 不管用
  • 因为每个模块最终向外 return 的是 module.exports
  • exports 只是 module.exports 的一个引用
  • 所以即便你为 exports = xx 重新赋值,也不会影响 module.exports
  • 但是有一种赋值方式比较特殊:exports = module.exports 这个用来重新建立引用关系的
  • 总结:最后 return 的是 module.exports,不是 exports,所以你给 exports 重新赋值不管用。 多个成员可以moudle.exports.xxx = xxxexpots.xxx = xxx,单个成员的时候只能module.exports = xxx

2.11 require优先缓存加载

a加载过b,当再次require时不会重新加载。可以拿到其中的接口对象,但是不会重复执行里边的代码。目的:避免重复加载,提高模块加载效率

2.12 require模块查找机制

  • 优先从缓存加载
  • 核心模块
  • 路径形式的文件模块 ./ ../
  • 第三方模块(凡是第三方模块都必须通过 npm 来下载)
  • 既不是核心模块、也不是路径形式的模块
    • 先找到当前文件所处目录中的 node_modules 目录
    • node_modules/art-template/
    • node_modules/art-template/package.json
    • node_modules/art-template/package.json 里main属性中就记录了 art-template 的入口模块
    • package.json 文件不存在或者 main 指定的入口模块是也没有。node 会自动找该目录下的 index.js
  • 如果以上所有任何一个条件都不成立,则会进入上一级目录中的 node_modules 目录查找
  • 一个项目有且仅有一个 node_modules 而且是存放到项目的根目录。最后找不到就会报错

__dirname和filename

  • __dirname 动态获取可以用来获取当前文件模块所属目录的绝对路径
  • __filename动态获取可以用来获取当前文件的绝对路径
  • 这两个都不受node命令所属路径影响

在文件操作中使用相对路径是不可靠的,因为在Node中文件操作的路径被设计为相对执行node命令所处的路径。要解决这个问题,我们只需要把相对路径变为绝对路径就可以了

以后在文件操作中使用的相对路径都统一转换为动态的绝对路径

3. nodemon自动重启模块

  • 全局安装 npm install -g nodemon
  • 本地安装 npm i nodemon -D
  • 启动应用 nodemon [your node app]

4. 中间件

中间件的本质就是一个请求处理方法,我们把用户从请求到响应的整个过程分发到多个中间件中去处理。这样做的目的是提高代码的灵活性,动态可扩展的。

4.1 应用程序级别中间件

万能匹配(不关心任何的请求路径和请求方法)

app.use(function (req, res, next) {
	console.log('Time');
	next();
})

只匹配以xxx开头的

app.use('/a', function (req, res, next) {
	console.log('time');
	next();
})

4.2 路由级别中间件

get:

app.get('/', funciton (req, res) {
	res.send('hello');
})

post:

app.post('/', funciton (req, res) {
	res.send('hello');
})

put:

app.put('/user', funciton (req, res) {
	res.send('hello');
})

delete:

app.delete('/user', funciton (req, res) {
	res.send('hello');
})

4.3 错误处理中间件

app.use(function (err, req, res, next){
	console.error(err.stack)
	res.status(500).send('Something broke')
})

4.4 内置中间件

  • express.static
  • express.json
  • express.urlencoded

4.5 第三方中间件

  • body-parser