使用node进行web开发

用户上网流程:

表面上看:打开浏览器——输入网址——跳转——上网。

背后的过程是什么呢?

http请求网址到指定的主机——服务器接收请求——服务器响应内容到用户浏览器——浏览器接收到数据,并根据接收到的信息进行处理,渲染出用户看到的界面。

名词解释:

客户端——用户浏览器;

服务端——服务端

现在再精简下描述:

由客户端发送一个http请求到服务端,服务端接收并处理请求,返回数据到客户端


搭服务器

收发数据遵循一定的规则————一般是http规则。

搭建服务器,处理http请求,需要node.js提供一个http模块。

//加载一个http模块
var http=require('http');
//通过http模块下的creatServer方法创建并返回一个服务器对象
var server=http.createServer();
//开启服务器,接收四个参数
// 参数第一个是端口,第二个是ip,第三个是链接等待队列的最大长度,第四个成功开启之后的回调
server.listen();

这个时候输入console.log(server.address()),结果返回:

{ address: '::', family: 'IPv6', port: 57379 }

port端口号每次都改变,所以一般要自己设置。端口号尽量设大点。

http - http模块 - require('http')

var http = require('http');

var server = http.createServer([requestListener])

–创建并返回一个HTTP服务器对象

–requestListener : 监听到客户端连接的回调函数

server.listen(port, [hostname], [backlog], [callback])

–监听客户端连接请求,只有当调用了listen方法以后,服务器才开始工作

–port : 监听的端口

–hostname : 主机名(IP/域名)

–backlog : 连接等待队列的最大长度

–callback : 调用listen方法并成功开启监听以后,会触发一个listening事件,callback将作为该事件的执行函数

listening事件:当server调用listen方法并成功开始监听以后触发的事件

error事件 : 当服务开启失败的时候触发的事件

–参数err : 具体的错误对象

全部代码如下,一个服务器就搭建完毕了。

//加载一个http模块
var http=require('http');
//通过http模块下的creatServer方法创建并返回一个服务器对象
var server=http.createServer();
//开启服务器,接收四个参数
// 参数第一个是端口,第二个是ip,第三个是链接等待队列的最大长度,第四个成功开启之后的回调 server.on('error',function (err) {//报错方法
console.log('错误信息:'+err); }); server.on('listening',function () {
console.log('服务器正在运行...');
console.log(server.address());
});//运行提示 server.listen(8088,'localhost');//绑定8088端口

输出结果:

服务器正在运行...
{ address: '127.0.0.1', family: 'IPv4', port: 8088 }

request事件

在上面的代码插入一段

server.on('request',function () {
console.log('有客户端请求了!')
});

然后通过浏览器输入127.0.0.1:8088,这时弹出会弹出相应的信息。

注意:之前提到的createServer方法。它其实接收一个回调函数,也就是说二者其实是一样的。

request事件 : 当有客户端发送请求到该主机和端口的请求的时候触发

仅仅接收请求是没有多大意义的。还需要对客户端的请求进行分析。

  • 参数request : http.IncomingMessage的一个实例,通过他我们可以获取到这次请求的一些信息,比如头信息,数据等。
server.on('request',function (req,res) {
console.log('有客户端请求了!')
console.log(req);
});

重新载入页面,发现第一个参数request是一大串的信息。

里面有许多常用的方法。

  • httpVersion : 使用的http协议的版本,通常是1.1

  • headers : 请求头信息中的数据

  • url : 请求的地址

  • method : 请求方式(GET/POST)

  • 参数response : http.ServerResponse的一个实例,通过他我们可以向该次请求的客户端输出返回响应

    比如说请求发过来了,但是客户端一直在等待,而服务器未向客户端发送任何数据。可以通过server.timout方法设置最长等待时间。

  • write(chunk, [encoding]) : 发送一个数据块到响应正文中,数据块,编码

  • end([chunk], [encoding]) : 当所有的正文和头信息发送完成以后调用该方法告诉服务器数据已经全部发送完成了,这个方法在每次完成信息发送以后必须调用,并且是最后调用.

server.on('request',function (req,res) {
console.log('有客户端请求了!');
res.write('朕知道你发请求了','utf-8');//光是写入还不行,必须告诉客户端写完了
res.end();
//console.log(res);
});

客户端再刷新的结果,厉害了:



你也可以在你的文档里写如一段html代码。还可以设置头信息。

  • statusCode : 该属性用来设置返回的状态码
  • setHeader(name, value) : 设置返回头信息
  • writeHead(statusCode, [reasonPhrase], [headers])//状态码(200,404等),

    状态码可以通过输入http.STATUS_CODES点击进行查看

    这个方法只能在当前请求中使用一次,并且必须在response.end()之前调用

    res.writeHead(200,'SUNNY');//定义成功时的描述文字

请求参数req里的url处理

上面的服务器有重大的缺陷。url无论输入localhost/1....后面长度无论怎样,返回的都是一个信息。

以下我们用case来模拟首页('/'),个人中心('/user')和404('defult')的响应情况

新建一个服务器。

var http=require('http');
var server=http.createServer(); server.on('request',function (req,res) {
//通过req的url属性回应数据
//?后面的部分是query string查询字符串
console.log(req.url)
});
server.listen(8089,'localhost');

当访问localhost:8089/xxx时,打印出来的url为/xxx

再分析下url对象这个东西。路径名有时候是非常1复杂的,包含?等等参数。对url进行预处理很有必要,这就涉及到url对象

var http=require('http');
//请求url模块,并把url序列化想要的格式
var url=require('url'); var server=http.createServer(); server.on('request',function (req,res) {
//通过req的url属性回应数据
//?后面的部分是query string查询字符串
//console.log(req.url)
var urlStr=url.parse('http://www.baidu.com/a/index.html?c=2');
console.log(urlStr);
}); server.listen(8089,'localhost');

得到的打印出来的是



分析上面的内容发现,我们需要urlStr.pathname

var http=require('http');
//请求url模块,并把url序列化想要的格式
var url=require('url'); var server=http.createServer(); server.on('request',function (req,res) {
//通过req的url属性回应数据
//?后面的部分是query string查询字符串
//console.log(req.url)
var urlStr=url.parse(req.url);
//console.log(urlStr);
switch(urlStr.pathname){
case '/':
//首页,没有什么后缀
res.writeHead(200,{
'content-type':'text/html;charset=utf-8'
});
res.end('<h1>首页</h1>');
break;
case '/user':
//用户首页
res.writeHead(200,{
'content-type':'text/html;charset=utf-8'
});
res.end('<h1>个人中心</h1>');
break;
default:
res.writeHead(404,{
'content-type':'text/html;charset=utf-8'
});
res.end('<h1>404</h1>');
//处理其他情况
break;
}
}); server.listen(8089,'localhost');

那么url处理就算成功了。

表现和行为的分离

上面的代码中,每次针对每个页面输入不一样的内容,看起来是非常麻烦的。

作为规则,把html写进代码也是不符合规范的。也不利于维护。

所以我们需要用res的方法把它读取出来,再放到页面上去。

可以在同目录下新建一个html文件夹,创建首页(index.html)、用户中心(user.html)、404.html并写上各自的内容。然后用fs对象来读它。

var http=require('http');
var url=require('url');
var fs=require('fs'); var server=http.createServer();
var htmlDir='./html/'; server.on('request',function (req,res) {
var urlStr=url.parse(req.url);
//console.log(urlStr);
switch (urlStr.pathname){
case '/':
sendData(htmlDir+'index.html',req,res);
break;
case '/user':
sendData(htmlDir+'user.html',req,res);
break;
default:
sendData(htmlDir+'404.html',req,res);
break;
}
}); //应该定义一个方法,当根据路径来读取页面,然后把所需要的页面返回出去。
//三个参数:file是文件路径
function sendData(file,req,res) {
//这个方法的核心是读取文件内容。
fs.readFile(file,function (err,data) {
if(err){//如果读取失败,也就是404
console.log(err);
res.writeHead(404,{
'content-type':'text/html;charset=utf-8'
});
res.end(data);
}else{
res.writeHead(200,{
'content-type':'text/html;charset=utf-8'
});
//console.log(data.toString());
res.end(data);
}
}); }
server.listen('8089','localhost');

效果就实现了。但实际上代码还存在很多不必要的case语句。尝试再修改:

var http=require('http');
var url=require('url');
var fs=require('fs'); var server=http.createServer();
var htmlDir='./html'; server.on('request',function (req,res) {
var urlStr=url.parse(req.url);
switch (urlStr.pathname){
case '/':
sendData(htmlDir+'/index.html',req,res);
break;
default:
var urlPath=htmlDir+urlStr.pathname+'.html';
sendData(urlPath,req,res);
} }); //应该定义一个方法,当根据路径来读取页面,然后把所需要的页面返回出去。
//三个参数:file是文件路径,
function sendData(file,req,res) {
//这个方法的核心是读取文件内容。
fs.readFile(file,function (err,data) {
if(err){//如果读取失败,也就是404
console.log(file)
console.log(err);
fs.readFile('./html/404.html',function(err,data){
res.writeHead(404,{
'content-type':'text/html;charset=utf-8'
});
res.end(data);
});
}else{
res.writeHead(200,{
'content-type':'text/html;charset=utf-8'
});
//console.log(data.toString());
res.end(data);
}
}); }
server.listen('8089','localhost');

在这个代码下,尝试读取任何页面都有回应。我在html文件夹下创建了一个新的xxx.html读取也能正确。代码也简化了。这样基本效果就令人满意了。

遗憾的是当前还不支持css,js外链。

请求处理

为了说明原理,还是采用上面的例子代码。

  • get请求的数据处理

在html文件夹下创建一个login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<h1>这是登陆页面</h1>
<form action="/login/validate" method="get">
请输入用户名:<input type="text" name="username"><br>
请输入密码:<input type="text" name="password"><br>
<button type="submit">提交!</button>
</form>
</body>
</html>

如何获取用户提交过来的内容呢?在之前声明过的urlStr里面就包含了这些数据。

var http=require('http');
var url=require('url');
var fs=require('fs'); var server=http.createServer();
var htmlDir='./html'; server.on('request',function (req,res) {
var urlStr=url.parse(req.url); switch (urlStr.pathname){
case '/':
sendData(htmlDir+'/index.html',req,res);
break;
case '/login/validate':
//想得到用户提交过来的数据
//console.log(req.method)//提交方式get/post
console.log(urlStr);
break;
default:
var urlPath=htmlDir+urlStr.pathname+'.html';
sendData(urlPath,req,res);
} }); function sendData(file,req,res) {
//这个方法的核心是读取文件内容。
fs.readFile(file,function (err,data) {
if(err){//如果读取失败,也就是404
console.log(file)
console.log(err);
fs.readFile('./html/404.html',function(err,data){
res.writeHead(404,{
'content-type':'text/html;charset=utf-8'
});
res.end(data);
});
}else{
res.writeHead(200,{
'content-type':'text/html;charset=utf-8'
});
//console.log(data.toString());
res.end(data);
}
}); }
server.listen('8089','localhost');

登陆locoalhost:8089/login输入用户名密码,提交,发现打印出下列内容:



其中关键属性是query。

原来用户名是213,密码是231.

怎么实现自动化处理呢?node.js提供了必要的方法。

querystring模块

parse() : 将一个 query string 反序列化为一个对象

case '/login/validate':
//想得到用户提交过来的数据
//console.log(req.method)//提交方式get/post
var querystring=require('querystring');
console.log(querystring.parse(urlStr.query));
break;

结果打印出来一个json:{ username: '213', password: '231' }

实在是太方便了。有了它,就可以很方便的处理提交信息。

  • post请求的数据处理:req的data和end事件

    接下来把login.html页面的提交方式改为post

    post发送的数据会被写入缓冲区中,需要通过resquest的data事件end事件来进行数据拼接处理
if(req.method.toUpperCase()=='POST'){
var str='';
req.on('data',function (chunk) {
str+=chunk;
});
req.on('end',function () {
console.log(str);
})
}

打印出来的str为username=123&password=321

对于这样格式写成的数据自然想到了用querystring.parse()进行处理。处理完之后就是一个json对象了。

全部代码:

var http=require('http');
var url=require('url');
var fs=require('fs'); var server=http.createServer();
var htmlDir='./html'; server.on('request',function (req,res) {
var urlStr=url.parse(req.url); switch (urlStr.pathname){
case '/':
sendData(htmlDir+'/index.html',req,res);
break;
case '/login/validate':
//想得到用户提交过来的数据
//console.log(req.method)//提交方式get/post
if(req.method.toUpperCase()=='POST'){
var str='';
req.on('data',function (chunk) {
str+=chunk;
});
req.on('end',function () {
console.log(str);
var querystring=require('querystring');
console.log(querystring.parse(str));
}); }else if(req.method.toUpperCase()=='GET'){
var querystring=require('querystring');
console.log(querystring.parse(urlStr.query));
}
break;
default:
var urlPath=htmlDir+urlStr.pathname+'.html';
sendData(urlPath,req,res);
} }); function sendData(file,req,res) {
//这个方法的核心是读取文件内容。
fs.readFile(file,function (err,data) {
if(err){//如果读取失败,也就是404
console.log(file)
console.log(err);
fs.readFile('./html/404.html',function(err,data){
res.writeHead(404,{
'content-type':'text/html;charset=utf-8'
});
res.end(data);
});
}else{
res.writeHead(200,{
'content-type':'text/html;charset=utf-8'
});
//console.log(data.toString());
res.end(data);
}
}); }
server.listen('8089','localhost');

Node.js入门笔记(6):web开发方法的更多相关文章

  1. Node.js入门笔记(5):案例两则

    案例分析:前端自动化 1. 实现一个自动创建前端项目文件的js 通过node.js自动创建前端项目目录,包括js目录,js目录css目录,index.html和对应的内容. 初步的代码如下: var ...

  2. Node.js入门笔记(1):基本概念

    Node.js和JavaScript: 核心都是ECMAScrit,比如数据类型,语法结构,内置对象等等. 但是在js中顶层是window 在node中的不存在这个window(console.log ...

  3. Node.js入门笔记

    第一步自然是安装了.我是用Webstorm这个ide,安装分2步: 1.安装nodejs,下载Windows下的安装版本号.注意是以msi为扩展名的,然后下一步.没啥好说的,下载地址例如以下: 32位 ...

  4. Node.js入门笔记(2):全局对象(1)

    以下将以API文档为基础进行分析学习 global对象 这些对象在所有模块里都可用.有些对象不是在全局作用域而是在模块作用域里,这些情况下面文档都会标注出来. __filename--返回当前模块文件 ...

  5. Node.js入门笔记(4):文件系统(fs)

    文件系统(FileSystem) 文件系统模块 对于文件无外乎创建修改添加. File System - 文件系统模块 - require('fs') fs模块是核心模块,需要使用require导入后 ...

  6. Node.js入门笔记(3):全局对象(2)

    buffer 用于更好操作二进制数据,他是一个全局变量.类似数组. var a=new Buffer(); buffer类的三种实现 第一种创建方式 new Buffer(size);size[Num ...

  7. Node.js 入门资料

    小毛驴的阿凡提的 Node.js 入门笔记 http://www.cnblogs.com/Afanty/category/1007304.html

  8. 《Node.js入门》CentOS 6.5下Node.js Web开发环境搭建笔记

    近期想尝试一下英特尔的基于WebRTC协同通信开发套件,所以须要在本地搭建Node.js Web的开发測试环境. 这里讲的是CentOS 下的搭建方法.使用Windows的小伙伴请參考: <No ...

  9. Node.js 入门手册:那些最流行的 Web 开发框架

    这篇文章与大家分享最流行的 Node.js Web 开发框架.Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用程序,编 ...

随机推荐

  1. 大数据系列(3)——Hadoop集群完全分布式坏境搭建

    前言 上一篇我们讲解了Hadoop单节点的安装,并且已经通过VMware安装了一台CentOS 6.8的Linux系统,咱们本篇的目标就是要配置一个真正的完全分布式的Hadoop集群,闲言少叙,进入本 ...

  2. CocoaPod升级(以及ERROR: While executing gem ... (Errno::EPERM)解决办法)

    最近pods  0.39.0 升级1.1.1  ,发现一个坑,好纠结,好歹最后解决了 过程如下: 本来我想直接执行: $ sudo gem install cocoapods  // 安装cocoap ...

  3. 今天发现一些很有意思的ubuntu命令

    跑火车的sl/LS 终端数字雨cmatrix 可能是名言警句也可能是逗你玩的笑话的fortune/fortune-zh 一只会说话的牛 一只会吟诗的牛 上真牛喽! 炫酷 炫酷到这里了!!!

  4. WPF 无边框透明按钮

    在实际开发过程中,有时候要设置一个无边框的按钮,或者无边框的透明按钮. 按钮效果如下: 1.当你应用telerik组件中的Button时,这个直接就可以设置 telerik:StyleManager. ...

  5. maven核心,pom.xml详解(转)

    什么是pom?    pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件:开发者需要遵循的规则,缺陷管理系统,组织和licenses,项目的u ...

  6. 【原】移动web页面使用字体的思考

    回想2年前刚开始接触手机项目,接到PSD稿后,发现视觉设计师们喜欢用微软雅黑作为中文字体进行设计,于是我写页面的时候也定义 font-family 为微软雅黑,后来发到线上后,细心的产品经理发现页面的 ...

  7. Java面向对象 第一章 面向对象开发方法概述

    一.软件开发经历的生命周期: ①软件分析 ②软件设计 ③软件编码 ④ 软件测试 ⑤ 软件部署 ⑥软件维护 二.为了提高软件开发效率,降低软件开发成本,一个优良的软件系统应该具备以下特点: ① 可重用性 ...

  8. Spring中的JDK动态代理

    Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...

  9. iOS widget开发

    链接: iOS Widget开发 iOS开发之构建Widget iOS开发Widget iOS开发-widget基础 ios8新特性widget开发 ios 10 开发-widget实现 Widget ...

  10. LUA 利用#遍历表的问题

    tb ={ } t = { "hello", , , 'w', , tb } --~ 1 hello --~ 2 1 --~ 3 2 --~ 4 w --~ 5 4 --~ 6 t ...