Node的安装
把NODE安装后,如果我们没有修改安装的目录,那么默认是安装在:C:\Program Files\nodejs (大部分都是,如果自己修改了安装目录,自己去查找即可)
如果我们安装了NODE,那么它默认会把命令集成到DOS命令中,也就是DOS窗口中可以执行NODE命令
如果没有集成到DOS中,说明环境变量中缺少执行的文件,需要我们配置环境变量:
[WIN7]配置环境变量
我的电脑(右键) -> 高级系统设置 -> 环境变量
系统变量 -> Path -> 把原有的变量值保存一份
把NODE安装的目录添加到原有值的后面,例如:...;C:\Program Files\nodejs\
在把最新的结果重新写入到环境变量值中
Node的基本信息
何为NODE
NODE其实并非后台开发语言,我们了解的JAVA、PHP、C#、.NET(dot net)...才是后台开发语言,NODE仅仅是一个工具,一个基于V8引擎来渲染和解析JS的平台和工具(有点类似浏览器)
真实的开发中,我们一般都把NODE安装在服务器端,这样我们就可以在服务器端编写一些JS代码来处理服务器端的业务逻辑了 =>JS不仅仅可以在客户端浏览器中运行处理客户端业务逻辑(前端开发语言),也可以在服务器端的NODE环境下运行处理服务器端业务逻辑(后台开发语言),所以JS是全栈开发语言
NODE如何去执行JS代码
- 直接利用WB:在JS的空白处,右键,找到 Run xxx.js 就是在WB中调取NODE环境执行我们的JS代码
- 在当前JS所在的文件目录中打开DOS窗口,在DOS中执行 node xxx.js 也相当于把JS代码在NODE环境下执行了
- NODE的REPL命令:打开命令行输入node,出现 ‘ > ’说明已经进入了REPL
REPL(Read-Eval-Print Loop,简称REPL,“读取-求值-输出”循环)是一个简单的,交互式的编程环境。
REPL既可以作为独立单机程序,也可以被其他的程序包含在内的程序。
它提供了一种交互方式,即“执行程序,展现结果”。
它可以被用作debugging,testing 或者只是执行操作得到一些结果。
NODE的优势
- 快:基于V8引擎渲染和解析的
- NODE是单线程基于事件驱动的异步操作
- NODE提供了无阻塞的I/O操作
I/O:input/output 对文件的增删改查操作
- JS在客户端浏览器中运行的时候是不能对客户端本地的文件进行I/O操作的,因为我们要保证客户端的安全,JS做为前端开发语言是不可以操作客户端本地文件的,但是浏览器也提供了部分需要用户自主操作的功能,例如:上传图片
- JS在服务器端NODE环境下运行的时候可以对服务器上的文件进行I/O操作
学习NODE从模块开始
- 内置模块:自身带的 http、url、fs等
http:提供HTTP服务器功能
url:用于解析URL
fs:操作文件系统 - 自定义模块:自己写的模块
- 第三方模块:别人写好的,我们来调取使用
安装NODE之后自带npm命令,用来管理第三方模块的
所有我们需要调取的第三方模块都在https://www.npmjs.com/这个网站中
使用npm安装模块
1、安装到全局(global)
npm install xxx(模块名字) -g
npm uninstall xxx -g 卸载已经安装在全局的模块
2、安装在当前的项目下
npm install xxx(模块名字)
npm uninstall xxx
把模块安装到全局的问题:
- 以后不管是在哪一个项目目录下,我们都可以"通过使用命令操作的方式"来进行操作了,但是不能通过代码导入这个模块使用
- 安装在全局有很多时候会导致版本号冲突,例如:我之前安装的是LESS的2.7版本,以前的项目都是使用这个版本开发的,后来LESS升级了,升级到3.1,新版本和之前的版本不太一样,如果全局安装最新的,原来的项目就没办法使用LESS了
把模块安装在当前的项目中也有问题:
- 不能像安装在全局一样使用命令了,但是可以使用JS导入了
解决办法:在package.json 文件的scripts这个属性中进行配置
"scripts": {//->配置NPM脚本命令
"myFirst": "lessc ceshi.less ceshi.min.css -x"
}
以后再DOS中只需要执行npm run myFirst,就可以执行lessc -v这个命令了 - 在当前的项目中会有一个node_modules文件夹,里面存储的都是我们当前项目所需要使用的模块(这个文件夹很大的,传递给其他人非常的不好处理)
解决办法:上传gitHub的时候在项目目录中增加一个文件:.gitignore 这个文件中可以配置上传的时候忽略哪些文件,这些被忽略的文件就不在上传了 - 我们把一些第三方模块安装在A项目下,B项目不能直接的导入使用,如果需要的话还需要在B项目中重新的安装一遍
解决办法:需要在安装第三方模块的时候,把当前项目的所需要的模块清单写入到package.json的开发依赖项中
npm install xxx --save-dev 放在开发依赖模块清单中
npm install xxx --save 放在生产依赖的模块清单中
下一个B项目如果还是需要这些模块,我们就没有必要一个个的安装了,只需要把package.json文件拷贝到B项目中,然后执行 npm install 即可,这样的系统就会默认按照我们的开发依赖清单一个个的下载 =>"跑环境"
我们平时在做项目开发的时候,首先会在当前项目的根目录下执行:
npm init -y
这样执行完成后,会在当前项目的根目录下生成一个文件:
package.json
{
"name": "20170222", //->项目名称
"version": "1.0.0", //->项目的版本号
"description": "", //->当前项目的描述
"main": "temp.js", //->当前项目的入口
"dependencies": { //->当前项目依赖的第三方模块清单(生产:项目发布上线)
"less": "^2.7.2"
},
"devDependencies": {}, //->当前项目依赖的第三方模块清单(开发:项目正在研发)
"scripts": {//->命令脚本
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
- 模块间的相互调用
在NODE环境下,它认为每一个JS都可以理解为一个单独的模块,所以我们创建模块只需要创建JS文件即可;并且每一个模块和模块之间是互不干扰的,同时模块之间也可以通过特定方法相互调用一些语句
调用内置模块
require('http')//与导入自定义模块略有不同,参数内不需要有文件路径
require('url')
require('fs')
自定义模块 B模块调用A模块的sum方法:
A.js:
function sum() {...}
module.exports = {//此对象中的方法可为其他模块导入使用
sum: sum
};
B.js:
var a = require('./A');//代码导入A模块,可以使用A模块中module.exports中的方法,'./'为导入的模块的路径,表示当前目录,'A为导入模块的名字'
a.sum();//调用A模块中的sum函数
NODE中的内置模块
服务器端需要处理的事情
+ 在服务器上创建一个服务(监听一个端口)
+ 接收(解析)客户端的请求信息
+ 找到客户端需要的资源文件中的源代码
+ 把源代码返回给客户端
- HTTP 这个模块主要用于创建服务、监听端口、接收请求、返回内容的管理;
http.createServer([callback]):创建服务,默认遵循的是http传输协议
[callback]:此处的callback并不是当服务创建成功和=后就执行的,而是要等到客户端项向当前的服务发送请求时才会被触发,而且每次发送请求都会被触发,我们需要在这个回调函数中完成:接收解析、资源查找、源代码返回等操作
客户端如何迪昂当前服务发送请求?
http://localhost:8080/
向本地8080端口对应的服务发送请求
http://本机的ip地址:8080/
通过服务器的ip地址(外网ip,局域网ip)向当前服务器的8080服务发送请求
不仅会触发callback,还默认传递了2个参数:function(req.res){}
- req:request 请求对象,里面有很多属性和方法,存储了客户端的全部请求信息
+ req.url:储存的是客户端请求的资源文件路径以及问号传参的值,如:/css/index.css?name=zxt&age=27(字符串)
- res:response 响应对象,里面提供了很多方法,可供服务器把源代码返回给客户端
+ res.write([content]);向客户端响应内容(响应的内容是字符串)
+ res.end(); 结束向客户端的响应
+ res.writeHead;重写响应头
listen([port],[callback]):监听端口
[port]:端口号,取值范围0到65535,需要保持端口号的唯一性
[callback]:服务创建成功后,会执行这个回调函数,一般我们会输出一句话提示开发者创建成功
@return:类型,作用
例如
var http = require('http');
var server = http.createServer();
server.listen(80,function () {
console.log('success');
});
- URL 主要用来解析URL地址的
url.parse():解析一个完整的url(也可以不完整)的每一项
例如:
var url = require('url');
var str = "http://www.zhufengpeixun.cn:80/school/login.html?a=12$b=13#c"
cosnole.log(url.parse(str,true));
结果:
Url {
protocol: 'http:',
slashes: true,
auth: null,
host: 'www.zhufengpeixun.cn:80',
port: '80',
hostname: 'www.zhufengpeixun.cn',
hash: '#c',
search: '?a=12&b=13',
query: { a: '12', b: '13' },//第二个参数true会把问号传参解析成对象
pathname: '/school/login.html',
path: '/school/login.html?a=12&b=13',
href: 'http://www.zhufengpeixun.cn:80/school/login.html?a=12&b=13#c' }
-
FS
提供一些方法供开发者进行I/O操作fs.readFileSync([pathname]):同步读取文件中的内容,读取出的内容是字符串
fs.readFile([pathname][callback]):异步读取文件的内容
fs.writeFileSync([pathname],[content]):同步把内容写入到文件中,写入的内容需要是字符串格式,而且写入属于覆盖式写入
fs.writeFile
静态资源文件请求处理(HTML/CSS/JS/IMG(PNG、JPG、GIF...)/TXT...)
- 所有的静态资源文件都有一个共同的特征:都有后缀名,后缀名是由字母和数字组成的
- 分析规律得到,服务器端需要查找文件的路径地址只是在pathname前面加一个点即可
- 在客户端向我们的服务发送请求的时候,谷歌浏览器会默认请求一个图片"favicon.ico",但是在我们的服务器上是没有这张图片的,所以在使用FS查找内容的时候找不到,导致后台服务报错 =>如果客户端请求的资源文件在服务器上不存在,我们不能终止服务(不能让服务抛异常),只需要返回不存在即可
- 在IE浏览器中有问题:服务器端返回给客户端的都是字符串格式的数据(不管是HTML/CSS/JS...),对于谷歌浏览器来说,它比较的智能,会自动识别当前代码是什么类型的代码,然后进行解析和渲染;但是IE浏览器比较的弱智,不能识别具体的文件类型,都当成字符串了;
IE问题解决办法:在返回数据给客户端的时候,指定当前文件的MIME类型,告诉IE是什么类型的即可
MIME:每一种资源文件都有自己对应的类型,这些类型统称为MIME
* HTML -> text/html
* CSS -> text/css
* JS -> text/javascript
* PNG -> image/png
* ...
例:
//->导入需要的内置模块
var http = require('http'),
url = require('url'),
fs = require('fs');
//->创建服务监听端口
var server = http.createServer(function (req, res) {//创建服务
var urlObj = url.parse(req.url, true),//url解析,true参数表示将问号传参解析为对象
pathname = urlObj.pathname,//解析后的请求文件路径
query = urlObj.query;//解析后的问号传参对象
//->客户端静态资源文件请求的处理
var reg = /\.([0-9a-zA-Z]+)/i;
if (reg.test(pathname)) {
var conFile = null,
status = 200;
try {//容错处理,防止请求文件返回错误报错而阻塞代码执行
conFile = fs.readFileSync('.' + pathname);
} catch (e) {
conFile = 'not found~';
status = 404;
}
//->根据当前请求资源文件的后缀名,计算出文件的MIME类型
var suffix = reg.exec(pathname)[1].toUpperCase(),//后缀名捕获
suffixMIME = 'text/plain';//文件MIME类型默认为txt的
switch (suffix) {
case 'HTML':
suffixMIME = 'text/html';
break;
case 'CSS':
suffixMIME = 'text/css';
break;
case 'JS':
suffixMIME = 'text/javascript';
break;
}
//->在返回数据内容之前指定MIME类型(重写响应头)
res.writeHead(status, {
'content-type': suffixMIME + ';charset=utf-8;'
});
res.end(conFile);
}
});
server.listen(8080);//监听端口
网友评论