// 这是路由模块
// 1. 导入 express
const express = require('express')
// 2. 创建路由对象
const router = express.Router()
// 3. 挂载具体的路由
router.get('/user/list', (req, res) => {
res.send('Get user list.')
})
router.post('/user/add', (req, res) => {
res.send('Add new user.')
})
// 4. 向外导出路由对象
module.exports = router
此文章为黑马程序员视频参考笔记
仅供回顾内容参考
目录
介绍:
一、初识Node.js
1.1Node.js是什么,它是用来做什么的?
1.2node.js能干什么?
1.3前端用nodejs能做什么
1.4nodejs可以用来做什么
1.5nodejs 具体是做什么用的
1.6 node能做什么?
1.7node.js中的JavaScript运行环境
1.8node.js的学习路径
二、fs文件系统模块
2.1 读取指定文件中的内容
2.2 写入指定文件内容
2.3 成绩管理练习
2.4 fs模块-路径动态拼接问题
三、path路径模块
3.1 什么是path路径模块
3.3 时钟案列
四、http 模块
4.1什么是http模块
4.2创建基本的web服务器
五、node.js中的模块化
5.1模块化分类
5.2加载模块
5.3 模块作用域
5.5 module对象
5.6 exports对象
5.7 npm 与包
5.8 淘宝镜像 cnpm 配置
5.9 devDependencies 结点
5.9.1 nrm工具 解决下包速度慢的问题
5.9..2 项目包
对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好,V8引擎执行Javascript的速度非常快,性能非常好,基于ChromeJavaScript运行时建立的平台,用于方便地搭建响应速度快、易于扩展的网络应用。
发布于2009年5月,由RyanDahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型,让JavaScript运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。
功能模块:Node使用Module模块去划分不同的功能,以简化应用的开发。Modules模块有点像C++语言中的类库。
每一个Node的类库都包含了十分丰富的各类函数,比如http模块就包含了和http功能相关的很多函数,可以帮助开发者很容易地对比如http,tcp/udp等进行操作,还可以很容易的创建http和tcp/udp的服务器。
要在程序中使用模块是十分方便的,只需要如下:在这里,引入了http类库,并且对http类库的引用存放在http变量中了。
这个时候,Node会在我们应用中搜索是否存在node_modules的目录,并且搜索这个目录中是否存在http的模块。
如果找不到这个目录,则会到全局模块缓存中去寻找,用户可以通过相对或者绝对路径,指定模块的位置。
1.JavaScript为HTML设计师提供了一种编程工具HTML创作者往往都不是程序员,但是JavaScript却是一种只拥有极其简单的语法的脚本语言!
几乎每个人都有能力将短小的代码片断放入他们的HTML页面当中。
2.JavaScript可以将动态的文本放入HTML页面类似于这样的一段JavaScript声明可以将一段可变的文本放入HTML页面:document.write(""+name+"")3.JavaScript可以对事件作出响应可以将JavaScript设置为当某事件发生时才会被执行,例如页面载入完成或者当用户点击某个HTML元素时。
4.JavaScript可以读写HTML元素JavaScript可以读取及改变HTML元素的内容。
5.JavaScript可被用来验证数据在数据被提交到服务器之前,JavaScript可被用来验证这些数据。
6.JavaScript可被用来检测访问者的浏览器JavaScript可被用来检测访问者的浏览器,并根据所检测到的浏览器,为这个浏览器载入相应的页面。
7.JavaScript可被用来创建cookiesJavaScript可被用来存储和取回位于访问者的计算机中的信息
到底是什么?是一个JavaScript的编译环境,当前端语言JavaScript在写完之后可以交给进行编译和解释,它的存在对于JavaScript有了质的飞跃。
下面就是一个简单的命令#node目前,在大部分领域都占有一席之地,尤其是I/O密集型的。比如Web开发,微服务,前端构建等。
不少大型网站都是使用作为后台开发语言的,用的最多的就是使用做前端渲染和架构优化,比如淘宝双十一、去哪儿网的PC端核心业务等。
另外,有不少知名的前端库也是使用开发的,如Webpack是一个强大的打包器,React/Vue是成熟的前端组件化框架。
通常被用来开发低延迟的网络应用,也就是那些需要在服务器端环境和前端实时收集和交换数据的应用(API、即时聊天、微服务)。
阿里巴巴、腾讯、Qunar、百度、PayPal、道琼斯、沃尔玛和LinkedIn都采用了框架搭建应用。
另外,编写的包管理器npm已成为开源包管理了领域最好的生态,直接到2017年10月份,有模块超过47万,每周下载量超过32亿次,每个月有超过700万开发者使用npm。
是一个对于前端工作者不可或缺的工具。尤其是对于JavaScript有着巨大的提升,现阶段的应用已经有了非常蓬勃的发展。对于的学习和熟练运用,必不可少!
1、nodejs搭配MongoDB作后端;
2、nodejs搭配“终端”作前端的编译工具使用;
3、编辑一些小工具,例如“网络爬虫”啥的;
4、在不使用浏览器的控制台功能时,可用nodejs达到同样的目的
是一个运行在chromeJavascript运行环境下(俗称GoogleV8引擎)的开发平台,用来方便快捷的创建服务器端网络应用程序。
你可以把它理解为一个轻量级的JSP或PHP环境,但是用来开发Web应用的话,有时要便捷很多。很多人都不明白,为什么一个javascript的东西用在了服务器端的开发上。
一般认为javascript是浏览器端的脚本语言,但是google将其再开发,用来作为服务器端脚本环境,其性能自称比Python、Perl、PHP还要快。
的最大优点是处理并行访问,如果一个web应用程序同时会有很多访问连接,就能体现使用的优势。另一个好处是,使用javascript作为服务器端脚本语言,可以消除一些与浏览器端js脚本的冲突。
甚至发挥javascript动态编程的特性,在服务器与浏览器之间建立直接的动态程序。
是一个运行在chromeJavascript运行环境下(俗称GoogleV8引擎)的开发平台,用来方便快捷的创建服务器端网络应用程序。
的优点是:
1、处理并行访问,如果一个web应用程序同时会有很多访问连接,就能体现使用的优势。
2、使用javascript作为服务器端脚本语言,可以消除一些与浏览器端js脚本的冲突。
甚至发挥javascript动态编程的特性,在服务器与浏览器之间建立直接的动态程序。
1、浏览器是JavaScript的前端运行环境
2、Node.js是JavaScript的后端运行环境
3、Node.js中无法调用DOM和BOM等浏览器内置API
//引入fs模块读取文件内容
const fs=require('fs')
/**
* fs.readFile()
* path:必选参数,字符串,表示文件内容
* option:可选参数,表示以什么编码格式来读取文件
* callback:必选参数,文件读取完成后,通过回调函数拿到读取的结果
*/
fs.readFile('12.txt','utf8',function(err,dataStr){
console.log(err);//读取成功为NULL 读取失败为错误对象
console.log("---------");
console.log(dataStr);//读取成功 这是一段测试文本 读取失败为undefined
})
//向指定的文件写入内容
/**
* fs.writeFile()
* path:必选参数,字符串,表示文件路径
* data [option]:表示写入的内容
* callback:必选参数,文件写入完成后,通过回调函数拿到读取的结果
*/
fs.writeFile('1.txt','hahahahha',function(err){
console.log(err);//写入为NULL 写入失败为错误对象
})
const fs=require('fs')
fs.readFile('score.txt','utf8',(err,data)=>{
//判断是否读取成功
if(err){
return console.log('读取文件失败 \n'+err.message)
}
console.log("读取文件成功!"+data);
const arrOld=data.split(" ")
console.log(arrOld);
const arrNew=[]
arrOld.forEach(item => {
arrNew.push(item.replace('=',':'))
});
const newStr=arrNew.join('\r\n')
//writeFile 只能用来创建文件 不能用来创建路径 并且 重新写入的数据会覆盖原本文档中的数据
fs.writeFile('score.txt',newStr,(err)=>{
console.log(err);
if(err){
return console.log("写入文件失败!"+err.message);
}
console.log("写入文件成功");
})
})
// __dirname 表示当前文件所处路径
console.log(__dirname);
const path =require("path")
// console.log(path);
/**
* path.join():可以把多个路径片段拼接为完整 的路径字符串
* path.join([...paths])
* ...paths 路径片段的序列
* 返回值
*/
const pathStr= path.join('/a',"/b/c","../../","/d","/e")// ../会抵消前面一个路径 如/c就会被抵消掉
console.log(pathStr);//打印出来为 \a\d\e 几个../就抵消前面几个
/**
* path.basename(path[,ext]) //获取文件路径名
* path必选参数,表示一个路径的字符串
* ext可选参数,表示文件扩展名
* 返回:表示路径中的最后一部分
*/
var fpath="/a/b/c/index.html"
var fullname= path.basename(fpath)
console.log(fullname); //输出 index.html
var fullname= path.basename(fpath,".html")
console.log(fullname); //输出 index
/**
* path.extname() 获取文件扩展名部分
*
*/
var fpath="/a/b/c/index.html"
let fext= path.extname(fpath)
console.log(fext);//.html
const fs= require('fs')
const { basename } = require('path')
const path =require("path")
// 定义正则表达式
/**
* /s 表示匹配空白字符
* /S表示匹配非空白字符
*
*/
const regStyle=/',"")
console.log(newCSS);
// 将提取出来的内容放在index.css中去
fs.writeFile(path.join(__dirname,"index.css"),newCSS,(err)=>{
if(err) return console.log('写入失败');
console.log('写入成功');
})
}
// 4.1 定义处理 js 脚本的方法
function resolveJS(htmlStr) {
// 4.2 通过正则,提取对应的 标签内容
const r2 = regScript.exec(htmlStr)
// 4.3 将提取出来的内容,做进一步的处理
const newJS = r2[0].replace('', '')
// 4.4 将处理的结果,写入到 clock 目录中的 index.js 文件里面
fs.writeFile(path.join(__dirname, './clock/index.js'), newJS, function(err) {
if (err) return console.log('写入 JavaScript 脚本失败!' + err.message)
console.log('写入 JS 脚本成功!')
})
}
// 5.1定义处理HTML文本
function resolveHTML(htmlStr){
const newHtml=htmlStr.replace(regStyle.exec(htmlStr),"")
.replace(regScript.exec(htmlStr),"")
//将替换好的文件写入html中
fs.writeFile(path.join(__dirname,"index.html"),newHtml,(err)=>{
if(err) return "写入HTML失败!"
console.log("写入html成功");
})
}
// 1.导入http模块
const http=require("http");
//调用http.createServer()方法 即可快速创建一个web服务器实列
//2.创建web 服务器实列
const server=http.createServer()
//使用服务器实验的.on()方法,为服务器绑定一个request事件
//3.为服务器石烈绑定request事件 监听客户端的请求
server.on('request',(req,res)=>{
// 只要有客户端来请求我们自己的服务器,就会触发request 事件,从而调用这个事件处理函数
console.log("someone require your web");
// console.log(res);
})
//调用服务器实列的.listen()方法 即可启动当前的web服务器是列
//4.启动服务器
server.listen(8080,()=>{
console.log('http://127.0.0.1:8080');
})
req res 的方法
/**
* req 是请求对象 包含了客户端相关的数据和属性
* res 是响应对象 包含了与服务器相关的数据和属性
*/
const url=req.url
const method=req.method
// console.log(url,method);
/**
* res.end()方法的作用
* 要发送到客户端的字符串
* 向客户端发送指定的内容,并结束这次请求的处理过程
*/
// res.end("浏览器界面")
/**
* 当发送内容包含中文的时候会出现乱码问题
* 为了防止中文乱码的问题,需要设置响应头
* Content-type 的值为 text/html;charset=utf-8
*/
res.setHeader('Content-type','text/html;charset=utf8')
res.end("浏览器界面")
// 3.2 把请求的 URL 地址映射为具体文件的存放路径
// const fpath = path.join(__dirname, url)
// 5.1 预定义一个空白的文件存放路径
let fpath = ''
if (url === '/') {
fpath = path.join(__dirname, './clock/index.html')
} else {
// /index.html
// /index.css
// /index.js
fpath = path.join(__dirname, '/clock', url)
}
注意:使用require方法加载其他模块时候,会执行其他模块中的代码
// 当前这个文件,就是一个用户自定义模块 m1.js
console.log('加载了06这个用户自定义模块')
//m2.js
const m1 = require('./m1.js') //可以省略.js
console.log(m1)
//输出 加载了06这个用户自定义模块
//{}
引入其他文件 无法访问其他文件中的变量 方法
防止全局变量污染的问题
js中是没有防止全局变量污染的
1.module对象
在每个.js文件自定义模块中都有一个module对象,它里面存储了和其当前模块有关的信息,打印如下:
// 在一个自定义模块中,默认情况下, module.exports = {}
const age = 20
// 向 module.exports 对象上挂载 username 属性
module.exports.username = 'zs'
// 向 module.exports 对象上挂载 sayHello 方法
module.exports.sayHello = function() {
console.log('Hello!')
}
module.exports.age = age
// 让 module.exports 指向一个全新的对象
module.exports = {
nickname: '小黑',
sayHi() {
console.log('Hi!')
}
}
//其他文件引用 打印出来就是{ nickname: '小黑', sayHi: [Function: sayHi] }
向外共享模块作用域中的成员
注意点:使用require()方法导入模块时,导入的结果,永远以module.exports指向对象为准。
// console.log(exports)
// console.log(module.exports)
// console.log(exports === module.exports) //true
const username = 'zs'
module.exports.username = username
exports.age = 20
exports.sayHello = function() {
console.log('大家好!')
}
// 最终,向外共享的结果,永远都是 module.exports 所指向的对象
//其他文件引用打印输出 { username: 'zs', age: 20, sayHello: [Function (anonymous)] }
方法一:
使用阿里定制的cnpm命令行工具代替默认的npm,输入以下代码
npm install -g cnpm --registry=http://registry.npmmirror.com
检查是否安装成功:
$ cnpm -v
安装成功之后,以后安装依赖包的方式和npm的是一样的,只是npm的命令换成是cnpm就可以了。
方法二:
a:单次使用:
npm install --registry=http://registry.npmmirror.com
b:永久替换:
在开发react-native的时候,不要使用cnpm,cnpm安装的模块路径比较奇怪,packager不能正常识别。
所以,为了方便开发,我们最好是直接永久使用淘宝的镜像源
直接命令行的设置
$ npm config set registry http://registry.npmmirror.com
手动修改设置
1.打开.npmrc文件(C:\Program Files\nodejs\node_modules\npm\npmrc,没有的话可以使用git命令行建一个( touch .npmrc),用cmd命令建会报错) 2.增加 registry =http://registry.npmmirror.com 即可。
如果需要恢复成原来的官方地址只需要执行如下命令:
npm config set registry https://registry.npmjs.org
检测是否安装成功:
npm config get registry
npm init -y //初始化包 快速创建一个package.json
如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDpendencies结点中,与之对应的,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到dependencies节点中去
//安装指定包,并记录到devDependencies节点中 npm i 包名 -D //注意:上述命令是简写形式,等价于下面完整的写法 npm install 包名 --sava-dev
通过查看包的官方文档来判断此包是否需要加入到devDependencies节点中
# 通过npm 包管理器,将nrm 安装为全局可用的工具 npm i nrm -g #查看所有可用的镜像源 nrm 1s #将下包的镜像源切换为taobao 镜像 nrm use taobao
/**
* 那些被安装到项目的node_modules目录中的包都是项目包
* 项目包又分两类,分别是:
* 1、开发依赖包(被记录到devDependencies节点中的包,只会在开发期间用得到)
* 2、核心依赖包(被记录到dependencies节点中的包,在开发期间和项目上线后都会用得到)
*
*/
npm i 包名 -D //开发依赖包(会被记录到devDependencies节点下)
npm i 包名 //核心依赖包 (会记录到dependencies节点下)
npm i 包名 -g //全局包 卸载全局去安装包 npm uninstall 包名 -g
/**
* 只有工具类的包才有全局安装的必要性 因为他们提供了好用的终端命令
* 判断某个包是否需要全局安装后才能使用,可以参考官网提供的使用说明即可
*/
// 1. 导入 express
const express = require('express')
// 2. 创建 web 服务器
const app = express()
// 4. 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容
app.get('/user', (req, res) => {
// 调用 express 提供的 res.send() 方法,向客户端响应一个 JSON 对象
res.send({ name: 'zs', age: 20, gender: '男' })
})
app.post('/user', (req, res) => {
// 调用 express 提供的 res.send() 方法,向客户端响应一个 文本字符串
res.send('请求成功')
})
app.get('/', (req, res) => {
// 通过 req.query 可以获取到客户端发送过来的 查询参数
// 注意:默认情况下,req.query 是一个空对象
console.log(req.query)
res.send(req.query)
})
// 注意:这里的 :id 是一个动态的参数
// username后面接?表示可选
app.get('/user/:ids/:username', (req, res) => {
// req.params 是动态匹配到的 URL 参数,默认也是一个空对象
console.log(req.params)
res.send(req.params)
})
// 3. 启动 web 服务器
app.listen(80, () => {
console.log('express server running at http://127.0.0.1')
})
const express = require('express')
const app = express()
// 在这里,调用 express.static() 方法,
// 快速的对外提供静态资源
/**
* 托管多个静态资源目录
* 多次调用app.use(express.static())
* ./files路径不会出现在url地址上
*/
app.use('/files', express.static('./files'))
app.use(express.static('./clock'))
app.listen(80, () => {
console.log('express server running at http://127.0.0.1')
})
使用方法 nodemon 项目名字
index.js
const express = require('express')
const app = express()
// app.use('/files', express.static('./files'))
// 1. 导入路由模块
const router = require('./03.router')
// 2. 注册路由模块
// /api 表示 请求前面必须加/api 才能访问到
app.use('/api', router)
// 注意: app.use() 函数的作用,就是来注册全局中间件
app.listen(80, () => {
console.log('http://127.0.0.1')
})
router.js
// 这是路由模块
// 1. 导入 express
const express = require('express')
// 2. 创建路由对象
const router = express.Router()
// 3. 挂载具体的路由
router.get('/user/list', (req, res) => {
res.send('Get user list.')
})
router.post('/user/add', (req, res) => {
res.send('Add new user.')
})
// 4. 向外导出路由对象
module.exports = router
express.josn() express.urlencoded()中间件使用
// 导入 express 模块 const express = require('express') // 创建 express 的服务器实例 const app = express() // 注意:除了错误级别的中间件,其他的中间件,必须在路由之前进行配置 // 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据 app.use(express.json()) // 通过 express.urlencoded() 这个中间件,来解析 表单中的 url-encoded 格式的数据 app.use(express.urlencoded({ extended: false })) app.post('/user', (req, res) => { // 在服务器,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据 // 默认情况下,如果不配置解析表单数据的中间件,则 req.body 默认等于 undefined console.log(req.body) res.send('ok') }) app.post('/book', (req, res) => { // 在服务器端,可以通过 req,body 来获取 JSON 格式的表单数据和 url-encoded 格式的数据 console.log(req.body) res.send('ok') }) // 调用 app.listen 方法,指定端口号并启动web服务器 app.listen(80, function () { console.log('Express server running at http://127.0.0.1') })
3. 什么是 CORS
CORS (Cross-Origin Resource Sharing,跨域资源共享)由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器是否阻止前端 JS 代码跨域获取资源。
浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了 CORS 相关的 HTTP 响应头,就可以解除浏览器端的跨域访问限制。
CORS 响应头部
响应头部中可以携带一个 Access-Control-Allow-Origin 字段,其语法如下:
Access-Control-Allow-Origin:
|* 其中,origin参数的值指定了允许访问该资源外域URL。
列如,下面的字段值将只允许来自 http://itcast.cn
如果指定了 Access-Control-Allow-Origin 字段的值为通配符 *,表示允许来自任何域的请求,示例代码如下:
CORS 响应头部 - Access-Control-Allow-Headers
默认情况下,CORS 仅支持客户端向服务器发送如下的 9 个请求头: Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type (值仅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一) 如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败!
CORS 响应头部 - Access-Control-Allow-Methods
默认情况下,CORS 仅支持客户端发起 GET、POST、HEAD 请求。 如果客户端希望通过 PUT、DELETE 等方式请求服务器的资源,则需要在服务器端,通过 Access-Control-Alow-Methods来指明实际请求所允许使用的 HTTP 方法。
示例代码如下:
客户端在请求 CORS 接口时,根据请求方式和请求头的不同,可以将 CORS 的请求分为两大类,分别是:
简单请求
请求方式:GET、POST、HEAD 三者之一
HTTP 头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
预检请求:
只要符合以下任何一个条件的请求,都需要进行预检请求:
请求方式为 GET、POST、HEAD 之外的请求 Method 类型
请求头中包含自定义头部字段 向服务器发送了 application/json 格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。
简单请求的特点:客户端与服务器之间只会发生一次请求。
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION 预检请求成功之后,才会发起真正的请求。