一. 安装及概述
1. 概述: Node.js 不是一门新的语言,是一个JavaScript运行环境, 简单的说 Node.js 就是运行在服务端的 JavaScript。
2. 特点:
1).单线程
2).异步的非阻塞I/O
3).事件驱动
3. 使用场景:
1).后台开发
2).使用node的npm功能,方便的安装,删除,替换第三方模块
3).node的兼容性较好,Windows,Linux,MacOS均可以使用node环境,node从0.6版本开始,只要装node,会顺带装npm
二. 模块
-
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Node环境中,一个.js文件就称之为一个模块(module)。
-
好处: 最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Node内置的模块和来自第三方的模块。使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。
-
注意: exports 和 module.exports 的使用 如果要对外暴露属性或方法,就用 exports 就行,要暴露对象(类似class,包含了很多属性和方法),就用 module.exports。
exports与module.exports的区别:*
exports是对module.exports的引用
外界require导入模块时,真正导入的是module.exports而不是exports -
http模块 分析Node.js 的 HTTP 服务器: 第一行请求(require)Node.js 自带的 http 模块,并且把它赋值给 http 变量。 接下来我们调用 http 模块提供的函数:createServer 。这个函数会返回 一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数, 指定这个 HTTP 服务器监听的端口号。 例: let http=require("http"); http.createServer(function (req,res) {}).listen(端口号);
http协议:
let http=require("http");
/*
* http协议:基于请求和响应的模式,如果服务器响应完毕,客户端与服务器断开连接,下次请求需要重新发起请求,http是典型的短连接
*
* createServer分两部分:
1.创建server
2.设置监听
req(requet对象)--请求对象
请求头/请求体
请求头:请求头很短,包含本次请求的基本信息
常用的req对象属性:
url--当前请求的路径和参数
method--当前请求的方式
请求体:当POST请求时,数据会存放在请求体里传送到后台,但是因为数据会很大,node不会依次传递完毕,会分段传递,所以我们需要监听两个事件保证数据获取的完整性和准确性
data--每当有一段数据传递过来时,data事件都会触发
end--当最后一段数据传递完毕时,end事件会触发
res(response对象)--响应对象
响应头/响应体
响应头:存储本次响应给前端数据的配置信息,如文件格式,编码格式等
res.writeHeader(响应码, {配置信息});第二个参数苏也可以不写.系统也会自动加一个,但是值是默认值
响应体:决定后台向前端返回什么
res.write()--可以写多次,也可以不写
res.end()--必须写,作用是结束本次响应,如果不写,前端会一直等待后台响应
* */
let server=http.createServer(function (req,res) {
console.log(req.url,req.method);
res.end("响应结束");
}).listen(7890);
//监听端口号
// server.listen(7890);
5.fs模块
6.node.js的核心思想之一: 模块(module)和包(package)
模块的本质是一个文件,该文件的类型可以是js,json,也可以是其他语言编译过后的文件(c,c++).
node对包的管理,遵循的是commonJS规范(规定了js脱离浏览器端之后的一些书写标准)
- 优点:方便代码的抽离和使用. * 为了方便实现模块化,node给每个文件都设置了requir和exports功能. * import 导入,export 导出 * require是为了引入外部的模块 * exports是当前文件如果被别的文件引入时的入口对象,而且是唯一入口对象
包的本质是一个文件夹(目录),包是由多个模块组成,npm管理的就是包
node对包的管理,遵循的是commonJS规范(规定了js脱离浏览器端之后的一些书写标准)
ECMSScript6====ECMAScript2015
commonJS规定,在创建或者下载包时,每个包里必须要有一个package.json文件,该文件里存储了与本包有关的所有配置信息(如包的入口文件) * node允许我们使用交互式的方式创建package.json文件 1.cd 文件夹路径 2. npm init / npm init -y
/* * 下载第三方的命令: * 1. npm i 包名 -- 下载包 * 2. npm i 包名@版本号 -- 下载对应版本的包 * 3. npm uni 包名 -- 移除包 * 4. npm uni 包名@版本号 -- 移除对应版本的包 * 5. npm i -- 根据package.json,安装所有包 * */
7.path模块
//引入path模块
//path node里专门用来处理路径的模块
let path=require("path");
//1.规范化路径
let pathStr='./a/b/c/../d';
let str=path.normalize(pathStr);
console.log(str);
//2.拼接路径
let str1=path.join("./","a/","b/","c/../","d");
console.log(str1);
//3.__dirname, __filename 这是node提供的全局变量,与path没有关系
console.log(__dirname, __filename);
//4.判断一个路径是否是绝对路径,以 / 开头的都是绝对路径
console.log(path.isAbsolute('a/b/c'));
//5.获取一个路径到另外一个路径之间的相对路径
let str2=path.relative("a/b/c/d/e","a/f/g");
console.log(str2);
//6. 获取当前文件所处的目录
let str3=path.dirname("a/b/c/d/n.txt");
console.log(str3);
//7.获取对应文件所在的路径中的最后一个部分
let str4=path.basename(__filename);
console.log(str4);
//8.获取对应文件的后缀
let str5=path.extname(__filename);
console.log(str5);
//9.对路径字符串进行解析 字符串-->对象
let str6=path.parse(__filename);
console.log(str6);
//10.对路径对象进行编码 对象-->字符串
let pathObj={
root: 'C:\\',
dir: 'C:\\Users\\lx\\Desktop\\a\\b',
base: 'c.html',
ext: '.html',
name: 'c'
};
let str7=path.format(pathObj);
console.log(str7);
8.url模块
let urlStr="http://www.baidu.com:8888/a/b/c/d/index.hmtl?name=nihao#sPage";
// #:哈希值,该值不会传递到服务器
//url模块,node里专门用来处理URL网址的模块
let url=require("url");
//1.将URL地址转化为对象
/*
* protocol: 'http:', 协议名
slashes: true, 协议名后面是否有斜杠
auth: null, 认证授权
host: 'www.baidu.com:8888', 域名+端口号
port: '8888', 端口号
hostname: 'www.baidu.com', 域名
hash: '#sPage', 哈希值
search: '?name=nihao', ?+参数列表
query: 'name=nihao', 参数列表
pathname: '/a/b/c/d/index.hmtl', 路径
path: '/a/b/c/d/index.hmtl?name=nihao', 路径+?+参数列表
href:
'http://www.baidu.com:8888/a/b/c/d/index.hmtl?name=nihao#sPage' 完整的url
* */
//parse方法的第二个参数是一个布尔值,作用,如果填true会把urlObj里query字段转化为对象
let urlObj=url.parse(urlStr,true);
console.log(urlObj.query.name);
三. 事件events 模块只提供了一个对象:
events.EventEmitter。EventEmitter 的核心就 是事件发射与事件监听器功能的封装。 EventEmitter 的每个事件由一个事件名和若干个参 数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件监听器。
当事件发射时,注册到这个事件的事件监听器被依次调用,事件参数作 为回调函数参数传递。
EventEmitter.on(event, listener)、emitter.addListener(event, listener) 为指定事件注册一个监听器,接受一个字 符串 event 和一个回调函数 listener。
四. get/post请求
// get请求
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);
// post请求
var http = require('http');
var querystring = require('querystring');
var util = require('util');
http.createServer(function (req, res) {
var post = ''; //定义了一个post变量,用于暂存请求体的信息
req.on('data', function (chunk) { //通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
post += chunk;
});
req.on('end', function () {
//在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
post = querystring.parse(post);
res.end(util.inspect(post));
});
}).listen(3000);
五. express
express模块--是node里对http模块的再次封装 Express是一个自身功能极简,完全是路由和中间件构成一个web开发框架:从本质上来说,一个Express应用就是在调用各种中间件
express.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>express框架</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<button>ajax_get</button>
<button>ajax_post</button>
<button>ajax_jsonp</button>
<script type="text/javascript">
$("button").eq(0).click(function () {
$.ajax({
url:"http://127.0.0.1:3333/ajaxGet",
type:"get",
data:{name:"nihao",age:20},
success:function (data) {
console.log(data);
}
});
});
$("button").eq(1).click(function () {
$.ajax({
url:"http://127.0.0.1:3333/ajaxPost",
type:"post",
data:{id:123,school:"郑州大学"},
success:function (data) {
console.log(data);
}
});
});
$("button").eq(2).click(function () {
$.ajax({
url:"http://127.0.0.1:3333/ajaxJsonp",
type:"get",
dataType:"jsonp",
//express发起jsonp请求时,jsonp字段为callback,不能修改或者省略jsonp字段,默认值就是callback
jsonp:"callback",
jsonpCallback:"getData"
});
});
function getData(data) {
console.log(data);
}
</script>
</body>
</html>
express.js
let express=require("express");
//node里的querystring模块,专门用来处理参数字符串
// let qs=require("querystring");
//创建服务器
let app=express();
//1.引入body-parser模块
var bp = require('body-parser');
//2.配置body-parser,让所有的post请求都支持body-parser模块,那么所有的req对象就会多一个body属性,里面存储了post请求过来的数据 如何让所有的路由都支持body-parser模块?--使用中间件实现
app.use(bp.urlencoded({extended:false}));
/*
* express方法调用返回的app有三个监听方法,实现了类似路由的功能,但是本质还是中间件
* get()--用来监听get请求
* post()--用来监听post请求
* all()--用来监听所有请求,一半用来处理跨域问题
*
* 监听方法的参数:
* 参数一:路由
* a.字符串,如"/favicon.ico","/2-ajax.html"."*";
* b.正则表达式
* 参数二:回调函数
* req对象:请求对象--常用属性:
* 1.query 参数对象
* 2.path 文件路径
* 3.hostname 服务器地址
* res对象:响应对象--常用方法:
* 1.res.json(对象)
* 2.res.jsonp(对象)
* 3.res.send(内容)
* 4.res.sendFile(文件路径)
* 5.res.setHeader()--设置响应头
* */
//响应首部 Access-Control-Allow-Headers 用于 preflight request (预检请求)中,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。简单首部,如 simple headers、Accept、Accept-Language、Content-Language、Content-Type (只限于解析后的值为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 三种MIME类型(不包括参数)),它们始终是被支持的,不需要在这个首部特意列出。
app.all("*",function (req,res,next) {
res.setHeader("Access-Control-Allow-Origin","*");
res.setHeader("Access-Control-Allow-Header","X-Requested-With");
res.setHeader('Access-Control-Allow-Methods', 'GET, POST,PUT,DELETE,OPTIONS');
next();
});
app.get("/",function (req,res) {
res.end("响应结束");
});
app.get(/^\/.+\.html$/,function (req,res) {
res.sendFile(__dirname+req.path);
// console.log(__dirname);
});
app.get("/favicon.ico",function (req,res) {
res.sendFile(__dirname+req.path);
});
app.get("/ajaxGet",function (req,res) {
if(req.query.name=="nihao" && req.query.age=="20"){
res.json({msg:"登陆成功"});
}else{
res.send("登录失败");
}
});
app.post("/ajaxPost",function (req,res) {
//express里,post请求来的数据不存放在req.query里,post的数据存储在req对象的body属性里,但是需要bodyparser模块的配合
/*var allData="";
req.on("data",function (chunk) {
allData+=chunk;
})
req.on("end",function () {
let queryObj=qs.parse(allData);
res.send(queryObj.id+queryObj.school);
})*/
// console.log(req.body);
if(req.body.id=="123" && req.body.school=="郑州大学"){
res.json({
msg:"登陆成功",
});
}else{
res.send("登录失败");
}
});
app.get("/ajaxJsonp",function (req,res) {
res.jsonp({id:123,name:"nihao",age:20,sex:"男"});
});
/*
* 中间件--语法:
* app.use(路由(可省略),回调函数(req,res,next));
* 中间件是在请求的开始和请求的结束之间插入一些额外的操作
* 使用场景:
* 1.处理特殊的请求设置,body-parser
* 2.实现CORS 跨域资源共享(cross-origin-resource-sharing)
* */
//监听端口
app.listen(3333);
用到更多:
1.安装模块命令后面为什么要加 --save??
--save表示,我们安装模块的时候,同时把它写到package.json 文件中。这时打开package.json 文件,我们看到多了一个dependencies字段,它包括了我们刚安装的express dependencies: 是项目运行时的依赖,就是程序上线后仍然需要依赖,比如express, 我们程序就是用express 写的,如果没有express, 我们的程序根本无法运行,更直白一点,dependencies 就是我们在程序开发的过程中手动require的模块
评论区