NodeJS是什么:
Ryan Dahl 把这个V8搬到了服务器上,用于做服务器的软件。
Node.js是一个专注于实现高性能Web服务器优化的专家,几经探索,几经挫折后 遇到V8而诞生的项目。
Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触角伸到了服务器端。(不是一种独立的语言)
和LAMP 有着很大的不同 有强大的伸缩能力 Node.js没有web容器
特点:
单线程:
JAVA PHP服务器会为每一个客户端连接创建一个2M新的线程 8G的服务器只能容纳4000用户。
Node.js而仅仅使用一个线程 当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制 ,让Node.js程序宏观上也是同步 和普通相比 容量增加了10倍
同时不再有线程创建、销毁的时间开销 但是因为是一个单线程,一旦线程奔溃,整个服务器奔溃
non-blocking I/O :在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码
由于Node.js中采用了非阻塞型I/O机制 因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的
执行效率。
当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。所以,这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。
event-driven
Node中一个时刻只能执行一个事件回调函数 但是在执行一个事件回调函数的中途,可以转而处理其他事件(事件队列里的事件)
================================安装 ==============================================
http://www.runoob.com/nodejs/nodejs-install-setup.html
Node.js是服务器的程序,写的js语句,都将运行在服务器上.
返回给客户的,都是已经处理好的纯html。
1//require表示引包,引包就是引用自己的一个特殊功能
2var http = require("http");
3//创建服务器,参数是一个回调函数,表示如果有请求进来,要做什么
4var server = http.createServer(function(req,res){
5 //req表示请求,request; res表示响应,response
6 //设置HTTP头部,状态码是200,文件类型是html,字符集是utf8
7 res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});
8 res.end("哈哈哈哈,我买了一个iPhone" + (1+2+3) + "s");
9});
10
11//运行服务器,监听3000端口(端口号可以任改)
server.listen(3000,"127.0.0.1");
Node.js没有根目录的概念,因为它根本没有任何的web容器!127.0.0.1:3000/fang fang不是一个文件名在Node一般值得是url路径处理函数
==========================HTTP模块==========================
你用啥,你就require啥。 相当于python 的import
1//这个案例简单讲解http模块
2//引用模块
3var http = require("http");
4
5//创建一个服务器,回调函数表示接收到请求之后做的事情
6var server = http.createServer(function(req,res){
7 //req参数表示请求,res表示响应
8 console.log("服务器接收到了请求" + req.url);
9 res.end();
10});
11//监听端口
server.listen(3000,"127.0.0.1");
设置一个响应头
res.writeHead(200,{"Content-Type":"text/plain;charset=UTF8"});
生成网页,然后利用fs
模块读取网页文件,将其返回。
var http = require('http');
var fs = require('fs');
http.createServer(function (request, response){
fs.readFile('data.txt', function readData(err, data) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end(data);
});
识别url 一般用 第一个就是url模块,第二个就是querystring模块
createServer 的回调函数中有一个req ,res
req.url 是url路径 他可以返回#之前所有的路径 其他的参数
method
:HTTP请求的方法。headers
:HTTP请求的所有HTTP头信息。setEncoding()
方法用于设置请求的编码。request.setEncoding("utf8");- addListener()
querystring可以把req.url拆成多个前端
var query=url.parse(req.url,true).query;
当用 域名/?name=1
就可以把后面一部分转为 query
当大量用户涌进来的时候,并不是先处理A的请求返回,再处理B ,而是事件环的机制
比如有大量文件读写操作,并不会等待加载完再处理别人的请求
===============================fs模块===============================
fs.mkdir("./album/aaa");
//stat检测状态
fs.stat("./album/bbb",function(err,data){
//检测这个路径,是不是一个文件夹
console.log(data.isDirectory());
});
失败案例:
==================================把异步变为同步的方法==================================
因为for 循环是异步语句
var http = require("http");
var fs = require("fs");
var server = http.createServer(function(req,res){
//不处理收藏夹小图标
if(req.url == "/favicon.ico"){
return;
}
//遍历album里面的所有文件、文件夹
fs.readdir("./album/",function(err,files){
//files : ["0.jpg","1.jpg" ……,"aaa","bbb"];
//files是一个存放文件(夹)名的数组
//存放文件夹的数组
var wenjianjia = [];
//迭代器就是强行把异步的函数,变成同步的函数
//1做完了,再做2;2做完了,再做3
(function iterator(i){
//遍历结束
if(i == files.length){
console.log(wenjianjia);
return;
}
fs.stat("./album/" + files[i],function(err,stats){
//检测成功之后做的事情
if(stats.isDirectory()){
//如果是文件夹,那么放入数组。不是,什么也不做。
wenjianjia.push(files[i]);
}
iterator(i+1);
});
})(0);
});
res.end();
});
server.listen(3000,"127.0.0.1");
应该用迭代的思想,先检查完这个,再检查下一个,迭代可以把异步转为同步
===================================静态资源管理====================================
只要建立了static 就可以把文件资源当成根目录保存,以后找不到的url会去static找文件
============================================2===================================================
/**
* Created by Danny on 2015/9/20 9:34.
*/
var http = require("http");
var fs = require("fs");
var url = require("url");
var path = require("path");
var server = http.createServer(function(req,res){
//得到地址
var pathname = url.parse(req.url).pathname;
//判断此时用户输入的地址是文件夹地址还是文件地址
//如果是文件夹地址,那么自动请求这个文件夹中的index.html
if(pathname.indexOf(".") == -1){
pathname += "/index.html";
}
//输入的网址是127.0.0.1/images/logo.png
//实际请求的是./static/images/logo.png
var fileURL = "./" + path.normalize("./static/" + pathname);
//得到拓展名
var extname = path.extname(pathname);
//把文件读出来
fs.readFile(fileURL,function(err,data){
//读完之后做的事情
if(err){
//文件不存在
res.writeHead(404,{"Content-Type":"text/html;charset=UTF8"})
res.end("404,页面没有找到");
}
//读完之后做的事情
getMime(extname,function(mime){
res.writeHead(200,{"Content-Type":mime})
res.end(data);
});
});
});
server.listen(80,"127.0.0.1");
function getMime(extname,callback){
//读取mime.json文件,得到JSON,根据extname key ,返回对应的value
//读取文件
fs.readFile("./mime.json",function(err,data){
if(err){
throw Error("找不到mime.json文件!");
return;
}
//转成JSON
var mimeJSON = JSON.parse(data);
var mime = mimeJSON[extname] || "text/plain";
//执行回调函数,mime类型字符串,就是它的参数
callback(mime);
});
}
==================================模块,包=============================================
自己写模块:需要需要将变量 exports.msg=msg 导出
f=require("包") 这个f就是一个盒子,可以通过盒子去取包里的变量
导出类:module.exports=构造函数;
如果没有./的话去node_modules找
require("bar") 引用文件夹
可以去npm下载模块
fs.readfile 找路径根据 cmd来找 如果要找的话
==================================post提交数据==================================
var http = require("http");
var querystring = require("querystring");
//创建服务器
var server = http.createServer(function(req,res){
//如果你的访问地址是这个,并且请求类型是post
if(req.url == "/dopost" && req.method.toLowerCase() == "post"){
var alldata = "";
//下面是post请求接收的一个公式
//node为了追求极致,它是一个小段一个小段接收的。
//接受了一小段,可能就给别人去服务了。防止一个过大的表单阻塞了整个进程
req.addListener("data",function(chunk){
alldata += chunk;
});
//全部传输完毕
req.addListener("end",function(){
var datastring = alldata.toString();
res.end("success");
//将datastring转为一个对象
var dataObj = querystring.parse(datastring);
console.log(dataObj);
console.log(dataObj.name);
console.log(dataObj.sex);
});
}
});
server.listen(80,"127.0.0.1");
====================================formidable处理表单=====================================
var http = require("http");
var formidable = require('formidable');
var util = require("util");
//创建服务器
var server = http.createServer(function(req,res){
//如果你的访问地址是这个,并且请求类型是post
if(req.url == "/dopost" && req.method.toLowerCase() == "post"){
//Creates a new incoming form.
var form = new formidable.IncomingForm();
//设置文件上传存放地址
form.uploadDir = "./uploads";
//执行里面的回调函数的时候,表单已经全部接收完毕了。
form.parse(req, function(err, fields, files) {
if(err){
throw err;
}
console.log(fields);
console.log(files);
console.log(util.inspect({fields: fields, files: files}));
//所有的文本域、单选框,都在fields存放;
//所有的文件域,files
res.writeHead(200, {'content-type': 'text/plain'});
res.end("成功");
});
}
});
server.listen(80,"127.0.0.1");
### Express框架
安装:npm install --save express 表示自动修改package.json文件,自动添加依赖项。
//导入模块 //实例化 express对象 //express对象 获取get请求 ...等等 //express对象.监听
app.set("view engine","ejs") 视图引擎使用ejs模块
安装 npm install ejs
一般来说 express 参数匹配上不会继续往下匹配
app.get("/",function (req,res,next) {
res.render("asda");
});
解决不会继续往下匹配问题:
调节匹配顺序:
方式一:
app.get("/:user/:pwd",function (req,res,next) {
user=req.params["user"];
pwd=req.params["pwd"];
console.log(user)
console.log(pwd)
console.log("1")
res.send(user+pwd)
});
app.get("/admin/123",function (req,res) {
res.send("i have a biaodan ")
});
上下互换
解决方法2:
1app.get("/:username/:id",function(req,res,next){
2 var username = req.params.username;
3 //检索数据库,如果username不存在,那么next()
4 if(检索数据库){
5 console.log("1");
6 res.send("用户信息");
7 }else{
8 next();
9 }
10});
11
12app.get("/admin/login",function(req,res){
13 console.log("2");
14 res.send("管理员登录");
});
但是next()有个问题就是send之后再往页面上又send一次就会出问题
路由get、post这些东西,就是中间件,中间件讲究顺序,匹配上第一个之后,就不会往后匹配了。next函数才能够继续往后匹配。
app.use()也是一个中间件,他匹配出来的url可以有其他方法
req.originalUrl /admin/aa/bb/cc/dd
req.baseUrl /admin
req.path /aa/bb/cc/dd
- /当你不写路径的时候,实际上就相当于"/",就是所有网址
渲染内容:res.render()
如果不想使用views文件夹,想自己设置文件夹名字,那么app.set("views","aaaa");
设置模板引擎
app.set("views","aaaa");
res.send() Content-Type头部和200状态码 但是他可以能够自动设置MIME类型
如下:
res.status(404).send('Sorry, we cannot find that!');
res.set('Content-Type', 'text/html');
get 请求可以用 req.query
post 可以用 req.body 但是之前必须使用body-parser模块 但如果表单中含有文件上传,那么还是需要使用formidable模块。
得到post 的数据
var express=require("express");
var app= express();
var bodyparse=require("body-parser");
app.use(bodyparse.urlencoded({ extended: true }))
app.set("view engine","ejs");
app.get("/",function(req,res){
res.render("asda")
});
app.post("/register" ,function(req,res){
console.log(req.body) #{"n1":"words"}
})
app.listen(3000);