观看黑马node.js教程
文章目录
3.4
执行node(P6)
- 代码写在js文件内
- 在该js所在文件夹内git bash here,输入 node 文件名
文件名不能叫node.js,否则执行命令后,会打开js文件
node 01.js //hello world!
读取文件(P7)
let fs = require('fs');
fs.readFile('./txt文件/01.txt',function(error,data){
if(error){
console.log('Error!');
}
else{
console.log(data.toString());
}
});
简单http服务(P8)
let http = require('http'); //引入http模块
let server = http.createServer(); //创建服务器
server.on('request',function(){
console.log("接收到请求");
})
server.listen(3000,function(){ //3000是端口号
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问');
})
先输入node …
然后把该url复制到浏览器最上方框框内,回车,跳出"接收到请求"
ctrl + c 关闭服务器
发送响应(P9)
let http = require('http'); //引入http模块
let server = http.createServer(); //创建服务器
server.on('request',function(request, response){
console.log("接收到请求,路径是:" + request.url);
let reg01 = new RegExp("login","i");
let reg02 = new RegExp("register","i");
let reg03 = new RegExp("haha","i");
console.log()
if(reg01.test(request.url)){
//可以let url = request.url,可以变得更简洁
response.write("login!");
}
if(reg02.test(request.url)){
response.write("register!");
}
if(reg03.test(request.url)){
response.write("Hahahaha!");
}
response.end();
//可以end的同时发送响应数据,如response.end("hello world") 等价于先write再end
})
server.listen(3000,function(){ //3000是端口号
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问');
})
发送对象(P11)
let http = require('http'); //引入http模块
let server = http.createServer(); //创建服务器
server.on('request',function(req,res){
console.log('收到请求了,请求路径是:' + req.url);
let url = req.url;
let reg01 = new RegExp("products","i");
if(reg01.test(url)){
let productsArr = [{
name: 'Apple X',
price: 8888
},
{
name: 'Pine X',
price: 5000
},
{
name: 'Chili X',
price: 1999
}
]
res.end(JSON.stringify(productsArr));
}
else{
res.end("404 Not Found !");
}
})
server.listen(3000,function(){ //3000是端口号
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问');
})
模块系统(P13)
除了引入核心模块,require可以在一个文件中引入另一个文件,但是存在模块作用域,即外部访问不到内部,内部也访问不到外部
想让模块间通信时,可以在被引文件中写入exports,如 a文件引入了b文件 require(’./b’),那么b文件内可以:
exports.foo = 'hello';
exports.add = function(x,y){
return x + y;
}
a文件内:
let bExports = require('./b');
console.log(bExports.foo);//hello
3.5
ip地址和端口号(P14)
ip地址定位某一台计算机,端口号定位该计算机上的应用程序
//写在server.on函数内:
console.log('请求我的客户端的地是',req.socket.remoteAddress,req.socket.remotePort);
//获取ip地址和端口号
只要发送请求,服务器就能获得ip地址和端口号
响应内容类型(P16)
let http = require('http');
let server = http.createServer();
server.on('request',function(req,res){
let url = req.url;
if(url === '/plain'){ //普通文本
res.setHeader('Content-Type','text/plain;charset=utf-8');
//防止乱码,引号内不能多空格
res.end('一行中文文本');
}
else if(url === '/html'){ //html
res.setHeader('Content-Type','text/html;charset=utf-8');
res.end('<h1>一段HTML</h1>');
}
})
server.listen(3000,function(){
console.log('Server is running...');
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问');
})
响应图片(P17)
let http = require('http');
let fs = require('fs'); //引入fs核心模块
let server = http.createServer();
server.on('request',function(req,res){
let url = req.url;
if(url === '/html'){
fs.readFile('./html/02.html',function(err,data){
if(err){
res.setHeader('Content-Type','text/plain;charset=utf-8');
res.end('文件读取失败,请稍后重试!');
}
else{
res.setHeader('Content-Type','text/html;charset=utf-8');
res.end(data); //html文件无需tostring
//修改html文件时,只需要在浏览器内刷新就能看到,不需要重开服务器,其它资源都同理
//只有修改了该js文件后,才需要重启服务器
}
})
}
else if(url === '/img'){
fs.readFile('./imgs/1.jpg',function(err,data){
if(err){
res.setHeader('Content-Type','text/plain;charset=utf-8');
res.end('文件读取失败,请稍后重试!');
}
else{
res.setHeader('Content-Type','image/jpeg');
res.end(data); //img文件也无需tostring
}
})
}
});
server.listen(3000,function(){
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问');
})
第一天总结(P18)
## 上午总结
- Node.js 是什么
+ JavaScript 运行时
+ 既不是语言,也不是框架,它是一个平台
- Node.js 中的 JavaScript
+ 没有 BOM、DOM
+ EcmaScript 基本的 JavaScript 语言部分
+ 在 Node 中为 JavaScript 提供了一些服务器级别的 API
* 文件操作的能力
* http 服务的能力
## 总结
- Node 中的 JavaScript
+ EcmaScript
* 变量
* 方法
* 数据类型
* 内置对象
* Array
* Object
* Date
* Math
+ 模块系统
* 在 Node 中没有全局作用域的概念
* 在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
* require 加载只能是执行其中的代码,文件与文件之间由于是模块作用域,所以不会有污染的问题
- 模块完全是封闭的
- 外部无法访问内部
- 内部也无法访问外部
* 模块作用域固然带来了一些好处,可以加载执行多个文件,可以完全避免变量命名冲突污染的问题
* 但是某些情况下,模块与模块是需要进行通信的
* 在每个模块中,都提供了一个对象:`exports`
* 该对象默认是一个空对象
* 你要做的就是把需要被外部访问使用的成员手动的挂载到 `exports` 接口对象中
* 然后谁来 `require` 这个模块,谁就可以得到模块内部的 `exports` 接口对象
* 还有其它的一些规则,具体后面讲,以及如何在项目中去使用这种编程方式,会通过后面的案例来处理
+ 核心模块
* 核心模块是由 Node 提供的一个个的具名的模块,它们都有自己特殊的名称标识,例如
- fs 文件操作模块
- http 网络服务构建模块
- os 操作系统信息模块
- path 路径处理模块
- 。。。。
* 所有核心模块在使用的时候都必须手动的先使用 `require` 方法来加载,然后才可以使用,例如:
- `var fs = require('fs')`
- http
+ require
+ 端口号
* ip 地址定位计算机
* 端口号定位具体的应用程序
+ Content-Type
* 服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
* 不同的资源对应的 Content-Type 是不一样,具体参照:http://tool.oschina.net/commons
* 对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
+ 通过网络发送文件
* 发送的并不是文件,本质上来讲发送是文件的内容
* 当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理
- 模块系统
- Node 中的其它的核心模块
- 做一个小管理系统:
+ CRUD
- Express Web 开发框架
+ `npm install express`
初步实现Apache(P21)
- apache软件默认有www目录,所有存放在www目录中的资源都可以通过网址来浏览
- 这样就能省去很多if判断了,输什么就能找到什么资源
let http = require('http');
let fs = require('fs');
let server = http.createServer();
let dir = 'D:/程序小白进阶之路/node.js';
server.on('request',function(req,res){
let url = req.url;
let filePath = '/html/02.html';
if(url !== '/'){
filePath = url;
}
fs.readFile(dir + filePath, function(err,data){
if(err){
return res.end('404 Not Found.');
}
res.end(data);
})
})
server.listen(3000,function(){
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问');
})
显示目录(P23)
先把文件夹拖入浏览器,然后获取其http,删除所有script,得到模板
<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
<meta charset="utf-8">
<meta name="google" value="notranslate">
<style>
h1 {
border-bottom: 1px solid #c0c0c0;
margin-bottom: 10px;
padding-bottom: 10px;
white-space: nowrap;
}
table {
border-collapse: collapse;
}
th {
cursor: pointer;
}
td.detailsColumn {
-webkit-padding-start: 2em;
text-align: end;
white-space: nowrap;
}
a.icon {
-webkit-padding-start: 1.5em;
text-decoration: none;
user-select: auto;
}
a.icon:hover {
text-decoration: underline;
}
a.file {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;
}
a.dir {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;
}
a.up {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;
}
html[dir=rtl] a {
background-position-x: right;
}
#parentDirLinkBox {
margin-bottom: 10px;
padding-bottom: 10px;
}
#listingParsingErrorBox {
border: 1px solid black;
background: #fae691;
padding: 10px;
display: none;
}
</style>
<title id="title"></title>
</head>
<body>
<div id="listingParsingErrorBox">糟糕!Google Chrome无法解读服务器所发送的数据。请<a
href="http://code.google.com/p/chromium/issues/entry">报告错误</a>,并附上<a href="LOCATION">原始列表</a>。</div>
<h1 id="header">D:/程序小白进阶之路/node.js/的索引</h1>
<div id="parentDirLinkBox" style="display:none">
<a id="parentDirLink" class="icon up">
<span id="parentDirText">[上级目录]</span>
</a>
</div>
<table>
<thead>
<tr class="header" id="theader">
<th id="nameColumnHeader" tabindex=0 role="button">名称</th>
<th id="sizeColumnHeader" class="detailsColumn" tabindex=0 role="button">
大小
</th>
<th id="dateColumnHeader" class="detailsColumn" tabindex=0 role="button">
修改日期
</th>
</tr>
</thead>
<tbody id="tbody">^_^</tbody>
<!--这里的^_^是后加的,用于替换-->
</table>
</body>
</html>
let http = require('http');
let fs = require('fs');
let server = http.createServer();
let wwwDir = 'D:/程序小白进阶之路/node.js';
server.on('request',function(req,res){
let url = req.url;
fs.readFile('./html/目录模板.html', function(err,data){
if(err){
return res.end('404 Not Found.');
}
fs.readdir(wwwDir,function(err,files){
if(err){
return res.end('Can not find www dir.');
}
let content = '';
files.forEach(function(item){
content += `
<tr>
<td data-value="apple/"><a class="icon dir" href="D:/程序小白进阶之路/node.js/">${item}/</a></td>
<td class="detailsColumn" data-value="0"></td>
<td class="detailsColumn" data-value="1509589967">2021/3/6 下午19:05:47</td>
</tr>
`
});
data = data.toString();
data = data.replace('^_^',content);
//把笑脸替换成目录
res.end(data);
});
});
})
server.listen(3000, function () {
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问');
})
在浏览器中使用art-template(P24)
下载模板引擎的方法:在想要下载的目录,git bash here,npm install art-template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./template/node_modules/art-template/lib/template-web.js"></script>
<script type="text/template" id="tpl">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>大家好,我叫:{{ name }}</p>
<p>我今年 {{ age }} 岁了</p>
<h1>我来自 {{ school }}</h1>
<p>我喜欢:{{each hobbies}} {{ $value }} {{/each}}</p>
</body>
</html>
</script>
<script>
var ret = template('tpl', {
name: 'Danmo',
age: 19,
school: '华中科技大学',
hobbies: [
'玩游戏',
'写代码',
'看动漫'
]
})
console.log(ret);
</script>
</head>
<body>
</body>
</html>
在node中使用art-template(P25)
let template = require('art-template')
let fs = require('fs')
fs.readFile('./html/03.html', function (err, data) {
if (err) {
return console.log('读取文件失败')
}
//render是模板引擎的方法,需要传入一个字符串
let ret = template.render(data.toString(), {
name: 'Danmo',
age: 18,
province: '',
hobbies: [
'写代码',
'唱歌',
'打游戏'
],
title: '个人信息'
})
console.log(ret)
})
模板引擎读取目录(P26)
let http = require('http')
let fs = require('fs')
let template = require('art-template')
let server = http.createServer()
let wwwDir = 'D:/程序小白进阶之路/node.js'
server.on('request', function (req, res) {
let url = req.url
fs.readFile('./html/template02.html', function (err, data) {
if (err) {
return res.end('404 Not Found.')
}
fs.readdir(wwwDir, function (err, files) {
if (err) {
return res.end('Cannot find dir.')
}
let htmlStr = template.render(data.toString(), {
title: '目录',
files: files
})
res.end(htmlStr)
})
})
})
server.listen(3000, function () {
console.log('服务器启动成功,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
node中的REPL(P34)
像浏览器的控制台一样,在任意目录下打开命令行窗口,输入node,即可进行REPL,退出时两次ctrl+c
read eval print loop(读取 执行 打印 等待下一次输入)
它的作用,主要是作一些API的测试
导出单个成员(P39)
-
之前说过的exports.xxx = … 导出的时候是一个对象,A文件内使用方法或属性还需要’点儿’
-
如果要直接导出函数、字符串等,可以用modules.exports,这个方法可以导出单个成员,如果有多个modules.exports,则下面会覆盖上面
A文件:
modules.exports = 'hello'
B文件:
let fooExports = require('./foo')
console.log(fooExports) //'hello'
modules.exports和exports的原理(P40)
只需记住以下要点:
- 因为每次写的 ‘.’ 太多了,node在模块内加了一句:exports = modules.exports
- 最后return的是modules.exports
- 对于引用数据类型,exports和modules.exports都相当于指针,如果直接对exports或者modules.exports赋值,指针就会指向别处;只要指针指向同一块区域,就可以随意为其添加属性和方法
这里关键是,对“引用数据类型”的理解
require加载规则(P42、P43)
优先从缓存加载
如果一个文件已经require过了,则不会再次加载该文件,再次require的意义,在于得到接口对象(let obj = require(…),目的在于得到obj)
第三方包查找规则
- 先找到当前文件所处目录中的 node_modules 目录
- 检索require(’ ')引号内的字符串,找到并进入该目录,比如我require(‘art-template’),就会进入/node_modules下的art-template目录
- 找package.json文件,找该文件内的"main",如果写的是"main":“foo.js”,就会加载foo.js中的内容,真正的代码是写在这个foo.js中的
- 如果找不到package.json文件,或者main指定的入口模块不存在,则默认加载index.js(index.js是默认备选项),如果index.js也没有,继续往上一级目录的node_modules目录中查找,如果直到当前磁盘根目录都没找到,就报错:can not find module
在项目中,一般只会在项目根目录下有一个node_modules目录
npm包(P44、P45、P46)
更多资料:Npm菜鸟教程
npm:node package manager
包说明文件
package.json
文件是包说明文件,建议每个项目都有一个,存放在项目根目录,从这个文件,可以得到包括 项目依赖哪些第三包… 等等的信息npm init
初始化项目即可生成package.json文件,这是个向导型命令,一问一答。
npm init
npm install 包名 --save
- 添加–save时,会在package.json文件中添加
"dependencies"
,从它我们可以看出该项目依赖了哪些第三方包,建议每次都添加–save - 如果有"dependencies",将 node_modules文件夹误删除时,可以直接通过
npm install
将所有依赖的第三方包下载回来
npm常用命令补充
- npm init -y 可以跳过向导,快速初始化
- npm i -S(install --save的缩写)
- npm i --global npm 不升级node,只升级npm版本(也可以用 -g)
- npm uninstall(缩写是un)
- npm help 查看使用帮助
- npm 命令 --help 查看指定命令的使用帮助
解决npm被墙问题
我不觉得npm下载速度慢,故这里先mark
-g 全局安装和本地安装的区别
npm的安装分为全局模式
和本地模式
。
一般情况下会以本地模式运行,包会被安装到和 应用程序代码的本地node_modules目录 下。
在全局模式下,Node包会被安装到 Node的安装目录下的node_modules 下。
全局安装命令为$npm install -g moduleName。