1. 介绍
没有DOM,BOM
在node.js这个js执行环境中为js提供了一些服务器级别的操作
例如文件读写
网络服务的构建
网络通信
http服务器
…等处理
2. 安装和使用
检查是否已经安装:
- 打开命令行
- 输入
node -v
或者node -version
- 若出现版本号,说明安装成功
编写并执行代码
- 在文件夹里创建
js
脚本文件,使用VS编写 - 打开终端(命令行),定位到脚本文件所属的目录(三种方法)
- Win+R,输入
cmd
,然后切换到文件所在目录 - 在文件所在地方右键->open Git bash here
- Shift+鼠标右键,找到"在此处打开
PowerShell
窗口"或"在此处打开命令行窗口"
- 输入
node 文件名
,执行对应的文件
注意:文件名不可以命名为node.js
,最好不用中文
01 读取文件
//1.使用require方法加载fs核心模块
//var后面的fs是变量名,可以随便起,但是括号中的'fs'不能改变
var fs =require('fs');
//2.读取文件
// 参数一是要读取文件的路径
// 参数二是一个回调函数
// 成功:
// data:数据
// error:错误对象
// 失败:
// data:undefined
// error:错误对象
fs.readFile('./data/hello.txt',function(error,data){
console.log(data.toString());
})
fs.readFile('./data/a.txt',function(error,data){
if(error){
console.log("读取文件失败");
}else{
console.log(data.toString());
}
})
data默认是二进制数据,可以通过.toString转换为咱们能识别的字符串或者显式指定 utf8
编码
- 不加
utf8
fs.readFile(dbPath, function (err, data) {
if (err) {
return callback(err);
}
console.log(data)
console.log(typeof data);//object
//JSON.parse() :字符串->对象
console.log(JSON.parse(data));
console.log(typeof JSON.parse(data)); //object
})
加
utf8
fs.readFile(dbPath,'utf8', function (err, data) { if (err) { return callback(err); } console.log(data) console.log(typeof data);//String //JSON.parse() :字符串->对象 console.log(JSON.parse(data)); console.log(typeof JSON.parse(data)); //object })
对比项 | 加 utf8 编码(场景 1) |
不加 utf8 编码(场景 2) |
---|---|---|
data 原始内容 |
直接显示 JSON 字符串(人类可读) | 显示 Buffer 二进制对象(人类难读,如 <Buffer ...> ) |
typeof data |
string (字符串类型) |
object (Node.js 中 Buffer 属于对象类型) |
JSON.parse(data) |
正常解析为 JavaScript 对象 | 也能解析(Node.js 自动把 Buffer 转字符串) |
本质区别 | 主动指定编码,让 fs.readFile 返回字符串 |
依赖 Node.js 隐式转换,data 是 Buffer 对象 |
. JSON.parse(data)
的兼容性
加
utf8
时:
data
是字符串,JSON.parse(data)
直接解析为 JavaScript 对象(如{ students: [...] }
),符合常规用法。不加
utf8
时:
JSON.parse
支持接收Buffer
对象!Node.js 会隐式地将Buffer
转为字符串(默认 UTF-8 解码),再解析 JSON。所以最终也能得到正确的 JavaScript 对象。注意:这种隐式转换是 Node.js 对
JSON.parse
的 “友好兼容”,但其他环境(如浏览器)的JSON.parse
不支持直接传Buffer
,只认字符串。
02写文件
fs.writeFile('文件名','要写入的内容',function(err){
})
这里面打函数只有一个参数err,失败的话是错误对象,成功的话是null
03 http
可以使用node轻松地构建一个Web服务器,Node中专门提供了一个核心模块:http
//1.http核心模块加载
var http=require('http');
//2.使用http.createSever()方法创建一个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
:请求对象
请求对象可以用来获取客户端的一些请求信息,例如请求路径
Response
:响应对象
响应对象用来给客户端发送响应消息,响应内容只能是二进制或字符串,其他的都不行
response
对象有一个方法,write可以用来给客户端发送响应数据,
write`可以使用很多次,但最后一定要有end来结束响应,否则客户端会一直等待
var http=require('http');
var server=http.createServer();
server.on('request',function(request,response){
console.log("收到请求了,请求路径是"+request.url);
// response
response.write('hello');
response.write('node.js');
response.end();
//更简单的方式:发送相应数据的同时结束响应
response.end('helloworld');
//以上方式不管发送什么请求,都只能响应固定的内容
})
server.listen(3000,function(){
console.log("服务器启动成功,可以通过http://127.0.0.1:3000/ 来进行访问");
})
var http=require('http');
var server=http.createServer();
server.on('request',function(request,response){
//根据不同的请求路径,发送不同的响应结果
var url=request.url;
if(url==='/'){
response.end('index page');
}else if(url==='/login'){
response.end('loginPage');
}else if(url==='/register'){
response.end('registerPage');
}else{
response.end('404 Not Found');
}
})
//浏览器默认是80端口,输入时可以不加端口号
server.listen(80,function(){
console.log("请求成功,可以访问了");
})
3. node中的js
EcmaScript
没有
BOM,DOM
核心模块
第三方模块
用户自定义模块
1. 核心模块
Node为JavaScript提供了很多服务器级别的API
.这些API
绝大多数都被包装到了一个具名的核心模块中了
例如文件操作的fs
核心模块,http
服务构建的http
模块,os
操作系统的信息模块
如果说要是用一个模块,就必须有
var fs=require('fs');
var http=require('http');
var os=require('os');
require是一个方法,作用是用来加载模块的
在node中,模块有三种:
具名的核心模块:
fs,http
等用户自己编写的文件模块,
相对路径必须加 ./,不可省略
可以省略后缀名:“js”
console.log('a start'); require('./b.js'); console.log('a end');
在Node中,没有全局作用域,只有模块作用域,外部访问不到内部,内部访问不到外部
既然是模块作用域,那如何让模块与模块之间进行通信?
有时候,我们加载文件模块的母的不是为了简单的执行里面的代码,而是为了使用里面的某个成员
require
方法有两个作用:
加载文件模块并执行里面的代码
拿到被加载文件模块导出的接口对象
在每个文件模块中都提供了一个对象:
exports
默认是一个空对象
我们要做的事把所有需要被外部访问的成员挂载到
exports
对象中
//a.js
var bExports=require('./b.js');
console.log(bExports.foo);
console.log(bExports.add(10,5));
console.log(bExports.age);
//b.js
var foo='bbb';
exports.foo='hello';
exports.add=function(x,y){
return x+y;
}
var age=18;
exports.age=age;
4. Node中的模块系统
使用node写应用程序主要是使用:
- ES语言
- 核心模块
- 文件操作fs
- http服务的http
- url路径操作模块
- path路径处理模块
- os操作系统信息
- 第三方模块
- art-template
- 必须通过npm下载才可以使用
- 自己写的模块
- 自己创建的文件
什么是模块化?
- 有文件作用域
- 有通信规则
- 加载(require)
- 导出
符合以上两点的就可以说符合模块化
CommentJS 模块规范
在node中的JS有一个重要概念:模块系统.
- 模块作用域
- 使用require方法来加载模块
- 使用exports接口对象来导出模块中的成员
1. 加载require
语法:
var 自定义变量名称=require('模块');
作用:
- 执行被加载模块中的代码
- 得到被加载模块中的
exports
导出接口对象
2.导出 exports
Node中是模块作用域,默认文件中所有的成员只在当前文件中有效
接口对象中对于希望可以被其他模块访问的成员,我们需要把这些公开的成员都挂载到
exports
中两种导出方式:
导出多个成员(必须在对象中)
//法一: exports.a=123; exports.b='hello'; exports.c=function(x,y){ return x+y; }; exports.d={ foo:'bar' }; //法二: module.exports={ add:function(x,y){ return x+y; }, str:'hello' }
导出单各成员(拿到的就是函数,字符串)
module.exports='hello'; //以下情况会覆盖(后者会覆盖前者): module.exports='hello'; module.exports=function(x,y){ return x+y; }
3.原理解析
在Node中,每个模块内部都有一个自己的module对象,该module对象中,有一个成员叫:exports,也是一个对象
如果你需要对外导出成员,只需要把导出的成员挂载到module.exports中
var module={
exports:{
foo;'bar'
}
}
在模块中,还有这么一句代码:
var exports=module.exorts;
exports
是module.exports
的一个引用
console.log(exports===module.exports);//true
exports.foo='bar';
//等价于
module.exports.foo='bar';
谁来require我,谁就得到module.exports
默认在代码的最后有一句:
return module.exports;
一定要记住,最后return的是module.exports而不是exports
当一个模块需要导出单个成员时,直接给exports赋值是不管用的,比如下面的语句就不行:
exports='hello';
原因:
示例:
var obj={};
var obj1=obj;
obj.foo='bar';
//此时obj1就是{foo:'bar'}
//继续
obj1.foo='hello';
//输出obj.foo,就是'hello'
//继续
obj1={};//这里相当于给他重新赋值了,此时obj和obj1指向的就不是一个引用了,二者的更改也不会影响到对方
obj1.foo='world';
//此时obj.foo还是hello
解释:
exports='hello'
相当于给exports重新赋值了,指向另一个对象了,但是最终返回的是module.exports,所以给exports重新赋值不管用
示例:
exports.a=123;
exports={};
exports.foo='bar';
//此时导出的是{a:123}
module.exports.b=456;
//此时导出的是{a:123,b:456}
示例:
module.exports='hello';
exports.foo='bar';//这一行添加的东西没啥用,不会被导出
原因:
本来二者是一个东西,但现在给module.exports
重新赋值了,他就指向另一个引用了,这时即使再给exports
赋值也没有用了,因为程序最终返回的是module.exports
5. 在node中使用art-template模版引擎
安装:使用命令
npm art-template
在需要使用的文件模块中加载art-template,使用require方法加载就可以了
`var template = require('art-template');`
查文档,使用模版引擎的API
//template.render('模版字符串',替换对象); var template = require('art-template'); var fs = require('fs'); fs.readFile('./tpl.html', function (err, data) { if (err) { return console.log('读取文件失败'); } // console.log(data); //data是二进制数据,而模版引擎的render方法需要接受的是字符串 //需要把data转换成字符串 // template.render('模版字符串',替换对象); var ret = template.render(data.toString(), { name: 'jack', age: 18, title:'个人信息' }); console.log(ret); })
模版引擎只认识
{{}}
,不管是字符串形式的还是什么,只要里面的变量名有意义,都会被替换
tpl.html
文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<p>大家好,我叫{{name}}</p>
<p>今年{{age}}岁了</p>
<script>
var foo='{{title}}';
</script>
</body>
</html>
打印ret:
url模块
- 使用:
var url=require('url');
url.parse( )
方法:var obj=url.parse('/postComment?name=我是美女&message=总结的好好',true)
打印obj,有一个
pathname
属性pathname: '/postComment'
有一个
query
属性obj.query:{ name: '我是美女', message: '总结的好好' }
true的作用:
将query转成对象的形式
加之前
'name=我是美女&message=总结的好好'
加之后
{ name: '我是美女', message: '总结的好好' }
6. Express
1. 准备
1.1安装
//安装package.json文件
npm init -y
//安装express
npm i-S express
1.2引包
var express=require('express');
1.3创建服务应用程序,也就是 http.creatServer
var app=express();
1.4当服务器收到get请求时.执行回调处理函数,使用这种方式就不用再添加请求头了
app.get('/',function(req.res){
res.send("找到了");
})
app.get('/about',function(req,res){
res.send("关于我");
})
1.5端口
app.listen(3000,function(){
console.log('qpp is running port 3000');
})
2.使用
2.1公开静态资源
法一:
app.use('/public',express.static('./public'));
这种方法可以通过/public/xxx访问public目录中的所有文件内容
法二:
app.use(express.static('./public'));
当省略第一个参数时,请求的url也要省略/public,否则访问不到
2.2在express中,可以直接使用 req.query
来拿到查询字符串参数
app.get('/about',function(req,res){
//在express中可以直接使用req.query来获取查询字符串参数
console.log(req.query);
res.send('关于我');
})
2.3基本路由:(映射关系)
- 请求方法
- 请求路径
- 请求处理函数
2.3.1get:
当以get方法请求/的时候,执行对应的函数
app.get('/',function(req,res){
res.send('Hello world');
})
在express中获取get表单数据
以前使用url.parse(req.url,true)来获取
现在直接使用req.query
2.3.2post:
当以post方法请求/的时候,执行对应的函数
app.post('/',function(req,res){
res.send('Got a Post request');
})
在express中获取post表单数据
原方法:
安装
npm install --save body-parser
配置
var express=require('express')
//1.引包
var bodyParser=require('body-parser');
var app=express();
//配置bode-parser,只要加入这个配置,则在req请求对象上会多出来一个属性:body
//也就是可以直接通过req.body来获取post请求体数据了
app.use(bodyParser.urlencoded({extended;false}));
app.use(bodyParserr.json())
但是Express 框架本身已经内置了替代方案,无需再额外依赖 body-parser
包,具体替换方式如下:
一、核心原因
body-parser
曾是 Express 生态里常用的请求体解析中间件,但从 Express 4.16.0 及更高版本开始,框架内置了 express.json()
和 express.urlencoded()
,功能与 body-parser
完全一致,官方因此标记 body-parser
为 “弃用”(继续用也能跑,但不推荐新项目使用 )。
二、替换方法(两步搞定)
1. 移除 body-parser
相关依赖(可选但推荐)
如果你是新项目,或想彻底清理旧依赖:
先卸载
npm uninstall body-parser
代码里删掉
require('body-parser')
的引入和相关app.use
配置。
2. 改用 Express 内置的解析中间件
直接用 Express 自带的 express.json()
和 express.urlencoded()
替换,示例代码:
const express = require('express');
const app = express();
// 解析 JSON 格式的请求体(替代 bodyParser.json())
app.use(express.json());
// 解析 URL 编码的请求体(替代 bodyParser.urlencoded({ extended: ... }))
app.use(express.urlencoded({ extended: false }));
// 后续路由可直接通过 req.body 获取参数
app.post('/your-route', (req, res) => {
console.log(req.body); // 解析后的数据
res.send('请求体已解析');
});
app.listen(3000, () => {
console.log('服务器启动,端口 3000');
});
关键说明:
express.json()
负责解析Content-Type: application/json
的请求体(如前端传 JSON 数据);express.urlencoded({ extended: false })
负责解析Content-Type: application/x-www-form-urlencoded
的请求体(如 HTML 表单提交);extended: false
表示使用内置的查询字符串解析器(更安全、轻量),若需支持复杂嵌套对象,可设为true
(但需额外安装qs
包 )。
只要执行了 res.redirect
/res.render
/res.send
中的任意一个,响应就会被 “终结”,express会自动结束相应
3.在art-template中配置express
3.1安装
npm install --save art-template
npm install --save express-art-template
3.2配置art-template模版引擎
- 第一个参数表示,当渲染以 .art或.html结尾的文件时,使用art-template模版引擎
- express-art-template 是专门用来在Express中把art-template整合到express中的,虽然这里不需要加载art-template,但是也必须安装,原因是express-art-template依赖了art-template
//这里写art时,则视图文件的后缀名也要改成art
//这里的art也可以改成html,这样视图文件的后缀名还保持html就可以了
app.engine('html', require('express-art-template'));
// res.render('html模版名',{模版数据}) render:渲染
3.3使用:
//找文件默认从views目录下开始找,所以要将所有的视图文件都放到views下
app.get('/', function (req, res) {
res.render('mainPage.html', {
comments: comments
});
})