前言:
承接上一节的内容,继续往下学习
web服务器:
Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务。它只需支持HTTP协议、HTML文档格式及URL,与客户端的网络浏览器配合。
在nodejs中,可以用短短几行代码就写出一个服务器:
//导入系统核心库——http
var http=require('http');
//createServer内部函数有两个参数
//一个是请求,一个是响应
//这两个参数实现的是‘流’,是流的实例
var server=http.createServer(function(request,response){
console.log('请求已经接收');
//将response像流那样操作,用一个写入流
//写头部流信息(参数是状态码和给浏览器传的内容类型)
response.writeHead(200,{'Content-Type':'text/plain'});
//服务器端向客户端(浏览器)写的文本内容
response.write('Do you love me?');
response.end();
})
//让服务器监听在一个端口上
server.listen(3000);
console.log("服务器监听在3000端口");
控制台会发现输出了两次:请求已经接收
因为浏览一次,客户端发送了两个请求
测试-返回一个JSON:
//导入系统核心库——http
var http=require('http');
//createServer内部函数有两个参数
//一个是请求,一个是响应
//这两个参数实现的是‘流’,是流的实例
var server=http.createServer(function(request,response){
console.log('请求已经接收');
//将response像流那样操作,用一个写入流
//写头部流信息(参数是状态码和给浏览器传的内容类型)
response.writeHead(200,{'Content-Type':'application/json'});
//一个json新对象
var myObj={
name:"luoluo",
job:"actor",
age:21
}
//stringify把myObj变成一个字符串类型的json
//即序列化
response.write(JSON.stringify(myObj));
response.end();
})
//让服务器监听在一个端口上
server.listen(3000);
console.log("服务器监听在3000端口");
在响应http界面:
#test.html
<!DOCTYPE html> <!--html5标准网页声明-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<table border="1" width="95%" cellspacing="0" cellpadding="3">
<tbody>
<tr align="center">
<td width="80">英雄</td>
<td> 技能</td>
</tr>
<tr align="center">
<td width="80">超人</td>
<td> 钢铁之躯</td>
</tr>
<tr align="center">
<td width="80">蝙蝠侠</td>
<td> 意志力</td>
</tr>
<tr align="center">
<td width="80">神器女侠</td>
<td> 真言套索</td>
</tr>
</tbody>
</table>
</body>
</html>
#app.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
//createServer内部函数有两个参数
//一个是请求,一个是响应
//这两个参数实现的是‘流’,是流的实例
var server=http.createServer(function(request,response){
console.log('请求已经接收');
//将response像流那样操作,用一个写入流
//写头部流信息(参数是状态码和给浏览器传的内容类型)
response.writeHead(200,{'Content-Type':'text/html'});
var ReadStream=fs.createReadStream(__dirname+"/test.html",'utf8');
//利用管道直接写入response
ReadStream.pipe(response);
})
//让服务器监听在一个端口上
server.listen(3000);
console.log("服务器监听在3000端口");
利用前面学的模块去重构文件:
#test.html
还和上面一样
#server.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
function startServer(){
var server=http.createServer(function(request,response){
console.log('请求已经接收');
response.writeHead(200,{'Content-Type':'text/html'});
var ReadStream=fs.createReadStream(__dirname+"/test.html",'utf8');
ReadStream.pipe(response);
})
server.listen(3000);
console.log("服务器监听在3000端口");
}
exports.startServer=startServer;
#app.js
var server=require('./server');
//server现在是一个对象
server.startServer();
路由:
路由:URL到函数的映射,或者说是请求资源的路标
要获得客户端的url信息,就要利用request
有心的朋友尝试输出一下我们的request.url就会发现它输出了一个 /
即127.0.0.1:3000对应的就是根目录
在上面的基础上,我们修改server.js,用if进行不同处理即可
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
function startServer(){
var server=http.createServer(function(request,response){
console.log('请求已经接收'+request.url);
if(request.url==='/'||request.url==='/home')
{
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/index.html",'utf8').pipe(response);
}else if(request.url==='/review'){
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/review.html",'utf8').pipe(response);
} else if(request.url==='/api/v1/records'){
response.writeHead(200,{'Content-Type':'application/json'});
var jsonObj={
name:"小明",
}
//把对象序列化
response.end(JSON.stringify(jsonObj));
}else{
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/404.html",'utf8').pipe(response);
}
})
server.listen(3000);
console.log("服务器监听在3000端口");
}
exports.startServer=startServer;
如此一来,就处理了127.0.0.1:3000、127.0.0.1:3000/home、127.0.0.1:3000/review、127.0.0.1:3000/api/v1/records还有其他url的404情况
nodejs中的等号很有趣,两个等号只是判断外在的值是否相等,不考虑类型,三个等号就是考虑类型的情况了(例如:1==”1″,返回true;1===”1″,返回false)
为了方便整理,我们来重构一下路由代码
做个route函数,先弄成这样
#route.js
function route(pathname){
console.log("Routing a request for"+pathname);
}
module.exports.route=route;
#server.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
function startServer(route){
var onRequest=function(request,response){
console.log('接收到了'+request.url);
route(request.url);
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
#app.js
//注意此时导出的是个对象
var server=require('./server');
var route=require('./route');
//server现在是一个对象
server.startServer(route.route);
我们再新建一个handler,js,在这个文件里进行处理
#route.js
var fs=require("fs");
function route(handle,pathname,response){
//typeof是用于判断类型
if(typeof handle[pathname]==='function'){
//传给handler的各位
handle[pathname](response);
}else{
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/404.html",'utf8').pipe(response);
}
}
module.exports.route=route;
#server.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
function startServer(route,handle){
var onRequest=function(request,response){
//传给route
route(handle,request.url,response);
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
#handler.js
var fs=require('fs');
function home(response){
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/index.html",'utf8').pipe(response);
}
function review(response){
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/review.html",'utf8').pipe(response);
}
function api(response){
response.writeHead(200,{'Content-Type':'application/json'});
var jsonObj={
name:"小明",
}
//把对象序列化
response.end(JSON.stringify(jsonObj));
}
module.exports={
home:home,
review:review,
api:api
}
#app.js
//注意此时导出的是个对象
var server=require('./server');
var route=require('./route');
var handler=require('./handler');
//建立一个空对象并且给空对象添加值
//key是路径,value是handler里面的函数
var handle={};
handle['/']=handler.home;
handle['/home']=handler.home;
handle['/review']=handler.review;
handle['/api/v1/records']=handler.api;
//server现在是一个对象
server.startServer(route.route,handle);
另外涉及到的三个html文档就不写出来了
至此,原先的路由代码就重构完成,以后添加删除都很方便了
GET或POST传递数据:
客户端发送请求一般有两种方式:在url地址中传递参数,或者通过表单去提交数据,比较常见的就是url带参的GET和提交表单的POST
GET:
例如:http://www.xxx.net/articles?kind=hot 中的 kind=hot ,就是给网站传了一个键值。
在上面的操作中,我们有很多路径,若访问者加上了GET参数(加上?a=b),我们要怎么舍去?a=b,还原路径呢?只要在上面的server.js中加上这几句就好了:
#server.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
//url工具库,可以对url进行处理
var url=require('url');
function startServer(route,handle){
var onRequest=function(request,response){
//只获取请求的路径名
var pathname=url.parse(request.url).pathname;
//传给route
route(handle,pathname,response);
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
然后我们访问127.0.0.1:3000/review?a=b就等同于访问127.0.0.1:3000/review
那要怎么取出来?a=b呢?
#server.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
var url=require('url');
function startServer(route,handle){
var onRequest=function(request,response){
//只获取请求的路径名
var pathname=url.parse(request.url).pathname;
//处理url后面的参数
var params=url.parse(request.url,true).query;
//传给route
route(handle,pathname,response,params);
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
url.parse()可以将一个完整的URL地址,分为很多部分,常用的有:host、port、pathname、path、query.
第二个参数为true,query属性会生成一个对象,如果为false,则返回url对象上的query属性会是一个未解析,未解码的字符串,默认为false
另外,parse的意思是解析,在c#中parse是强制类型转换的方法
如此一来,后面的route,handler的各个函数,都要加上形参param,然后我们就可以在handler中得到用户传来的param字段,然后根据需求进行处理。
我们就得到了Get请求的字段
POST:
表单传输数据,例如登录框(打开审查元素即可发现method=”post”)
先构造一个可以发送POST请求的html页面
#review.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<!--action属性指定向何处发送表单-->
<form action="/api/v1/records" method="POST">
姓名:<input type="text" name="name"/>
年龄:<input type="text" name="age"/>
<input type="submit" value="提交">
</form>
</body>
</html>
注意,表单发送到了/api/v1/records。然后处理其他js代码:
#serverjs
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
var url=require('url');
function startServer(route,handle){
var onRequest=function(request,response){
//只获取请求的路径名
var pathname=url.parse(request.url).pathname;
var data="";
//request是一个流,所以他也是继承事件的一个实例
request.on("error",function(err){
console.error(err); //错误的时候显示
}).on("data",function(chunk){
data+=chunk; //不断接收数据
}).on("end",function(){ //传给route
route(handle,pathname,response,data);
});
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
#handler.js
var fs=require('fs');
function home(response,param){
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/index.html",'utf8').pipe(response);
}
function review(response,param){
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/review.html",'utf8').pipe(response);
console.log(param);
}
function api(response,param){
response.writeHead(200,{'Content-Type':'application/json'});
//把对象序列化
response.end(JSON.stringify(param));
}
module.exports={
home:home,
review:review,
api:api
}
#route.js
var fs=require("fs");
function route(handle,pathname,response,params){
//typeof是用于判断类型
if(typeof handle[pathname]==='function'){
//传给handler的各位
handle[pathname](response,params);
}else{
response.writeHead(200,{'Content-Type':'text/html'});
fs.createReadStream(__dirname+"/404.html",'utf8').pipe(response);
}
}
module.exports.route=route;
#app.js
//注意此时导出的是个对象
var server=require('./server');
var route=require('./route');
var handler=require('./handler');
//建立一个空对象并且给空对象添加值
//key是路径,value是handler里面的函数
var handle={};
handle['/']=handler.home;
handle['/home']=handler.home;
handle['/review']=handler.review;
handle['/api/v1/records']=handler.api;
//server现在是一个对象
server.startServer(route.route,handle);
访问127.0.0.1:3000/review后填写数据,我们会跳转到/api/v1/records,并看见我们填写的数据以字符串形式出现(说明我们传给/api/v1/records的是个字符串)。
字符串显然是不能被利用的,接下来我们解析信息:
#server.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
var url=require('url');
var querystring=require('querystring');
function startServer(route,handle){
var onRequest=function(request,response){
//只获取请求的路径名
var pathname=url.parse(request.url).pathname;
var data="";
//request是一个流,所以他也是继承事件的一个实例
request.on("error",function(err){
console.error(err); //错误的时候显示
}).on("data",function(chunk){
data+=chunk; //不断接收数据
}).on("end",function(){ //传给route
//利用querystring.parse处理字符串数据
route(handle,pathname,response,querystring.parse(data));
});
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
考虑到POST和GET都有的情况,我们可以这样:
#server.js
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
var url=require('url');
var querystring=require('querystring');
function startServer(route,handle){
var onRequest=function(request,response){
//只获取请求的路径名
var pathname=url.parse(request.url).pathname;
var data="";
//request是一个流,所以他也是继承事件的一个实例
request.on("error",function(err){
console.error(err); //错误的时候显示
}).on("data",function(chunk){
data+=chunk; //不断接收数据
}).on("end",function(){ //传给route
if(request.method==="POST")
route(handle,pathname,response,querystring.parse(data));
else{
var params=url.parse(request.url,true).query;
route(handle,pathname,response,params);
}
});
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
最后,用Buffer.concat方法处理data,并且对POST表单长度做限制之后,最后的server就是这样:
//导入系统核心库——http
var http=require('http');
//核心库(fs)
var fs=require('fs');
var url=require('url');
var querystring=require('querystring');
function startServer(route,handle){
var onRequest=function(request,response){
//只获取请求的路径名
var pathname=url.parse(request.url).pathname;
var data=[];
//request是一个流,所以他也是继承事件的一个实例
request.on("error",function(err){
console.error(err); //错误的时候显示
}).on("data",function(chunk){
data.push(chunk); //不断接收数据
}).on("end",function(){ //传给route
if(request.method==="POST")
{ //表单内容过多则加以限制
if(data.length>1e6)
request.connection.destroy();
data=Buffer.concat(data).toString();
route(handle,pathname,response,querystring.parse(data));
}
else{
var params=url.parse(request.url,true).query;
route(handle,pathname,response,params);
}
});
}
var server=http.createServer(onRequest);
server.listen(3000);
console.log("服务器监听在3000端口");
}
module.exports.startServer=startServer;
博客:is-hash.com
商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢