专栏名称: 前端JavaScript
分享 | 学习 | 交流 | 原创 分享是学习的开始;学习不必要从头开始,是从现在开始;交流能沟通你我,提高你的学识;期待你的加入!!! web前端技术交流,JavaScript,HTML5,CSS3……
目录
相关文章推荐
51好读  ›  专栏  ›  前端JavaScript

【第2章第299回】Node的Web开发

前端JavaScript  · 公众号  · Javascript  · 2017-03-13 07:24

正文

文章共1862字,阅读大概需要13分钟。边敲边学大约需要42分钟

(欢迎参与文章最后的投票)


使用Node进行网络开发

用户在浏览器中输入网址 --> 获得网页的过程经历了几个步骤:


  1. 通过浏览器发送一个请求到服务器(期间经历的DNS解析、TCP3次握手连接)

  2. 服务器分析、处理用户的请求,并生产请求的内容,然后发送给浏览器

  3. 浏览器解析服务发送回的数据,生产网页

服务器

在HTTP协议中的服务器指:监听客户端的请求,并且根据请求的内容进行相应处理,返回响应给客户端。


Node中可以利用http模块进行Web服务器的搭建。


http模块

  1. http模块不是Node的核心模块,需要利用require()加载

  2. 使用http.createServer()方法创建一个http服务器,返回一个http服务器对象

    • 利用服务器对象进行开发

    • 接收的回调函数是监听到客户端请求时的回调函数

  3.  server.listen()方法可以开启Web服务,监听某台主机的某个端口

    • 参数是(port, hostname, backlog, callback)

    • port是监听主机的端口号;hostname是监听主机的IP地址;callback是服务器成功开启后的回调函数(开启服务器后,再连接数据库)

// 搭建    一个HTTP服务器,用于处理用户发送的http请求

// http模块不是核心模块,需要require()导入

var http = require('http');


// http模块的createServer()方法可以返回一个标准http服务器对象

// 通过服务器对象来进行开发

// callback是监听到客户端连接的回调函数

var server = http.createServer(callback);


// 服务器监听某个网卡上的某个端口,开启服务

// listen(port, hostname, backlog, callback)

// port是监听的端口,hostname是监听主机的ip地址,callback是服务器开启成功后的回调函数


// 服务器开启失败时触发error事件

server.on('error', function (err) {

  console.log(err);

})


// listening事件在服务器开启成功时触发

server.on('listening', function () {

  console.log('listening...8080');

})


// 监听来自客户端的请求事件,在接收到请求时触发

server.on('request', function () {

  console.log("there is a request");

})


server.listen(8080, 'localhost');

主要的事件

  1. 服务器开启失败的事件error的监听:server.on('errro', function(err) {})

  2. 服务器开启成功的事件listening的监听:server.on('listening', function(err) {}),可以写在server.listen()方法的回调函数中

  3. 服务器接收到请求的事件request的监听:server.on('request', function(err, req, res) {}),可以写在http.createServer()方法的回调函数中

参数对象

request事件接收两个参数:


  • request对象:提供客户端请求相关数据的对象,是http.IncomingMessage类的一个实例,有对应的属性与方法

    • httpVersion属性:使用的HTTP协议版本

    • header属性:请求头中相关的数据

    • url属性:

    • method属性:请求的方式

    • ...

  • response对象:服务端向客户端发送的响应数据对象,是http.ServerResponse类的一个实例

    • write(chunk, [encoding]):发送一个数据库到响应的正文(网页的内容数据)中,需要在发送完成后调用res.end()方法

    • end(chunk, [encoding], [callback]):在通过write()方法发送完所有正文和头信息后,需要res.end()告诉服务器数据全部发送完成。每个响应都必须调用res.end()方法,并且在最后调用。

    • 如果指定了 chunk,则它等同于调用 response.write(chunk, encoding) 之后调用 response.end(callback)

    • writeHeader(statusCode [, statusMessage] [, headers]):写入头信息,在res.write()前调用,并且一次响应中只能调用一次,头信息写在一个对象中

    • statusCode属性和setHeader()方法可以组合实现writeHeader()的功能

server.on('request', function (req, res) {

console.log("there is a request");

var chunk = '

hello world

';


// Buffer.byteLength(chunk)以字节为单位,告诉浏览器以纯文本解析传回的数据

res.writeHeader(200, 'OK', {'Content-type': 'text/plain', 'Content-length': Buffer.byteLength(chunk)});


res.end(chunk, 'utf-8');

})

url处理

根据用户请求的path返回不同的数据,使用req.url可以获取path信息。


  • req.url中?后面的部分叫做query。

  • Node下的url模块可以处理请求的中的req.url

  • 使用switch结构,为不同的pathname划分不同的逻辑处理方式

server.on('request', function (req, res) {

console.log(req.url);   //  req.url获取请求的路径path信息

var urlStr = url.parse(req.url);

switch(urlStr.pathname) {

  case '/':  // 首页

res.writeHeader(200, 'OK', {'Content-type': 'text/plain'});

res.end('

首页

', 'utf-8');

break;


  case '/users':  // 用户页

res.writeHeader(200, 'OK', {'Content-type': 'text/plain'});

res.end('

用户页

', 'utf-8');

break;


  default :  // 不存在

res.writeHeader(404, 'Not Found', {'Content-type': 'text/plain'});


res.end('

出错

', 'utf-8');

break;

}

})

使用fs模块实现行为与表现分离

根据用户不同访问的不同路径,执行不同操作,读取不同页面


server.on('request', function (req, res) {

  console.log(req.url);

  var urlStr = url.parse(req.url);


  switch(urlStr.pathname) {

    case '/':  // 首页

      sendData(htmlDir + '/index.html', req, res);  // 请求不同的路径,读取不同的页面返回给客户端

      break;


    case '/users':  // 用户页

      sendData(htmlDir + '/user.html', req, res);

      break;


    default :  // 不存在

      sendData(htmlDir + '/404.html', req, res);

      break;

  }

});


//  每次请求都读取静态页面,再输出。   fs.readFile()方法封装了fs.open()、fs.read()和fs.close()方法

// fs.readFile()返回值是原始的buffer对象

function sendData(file, req, res) {

  fs.readFile(file, function (err, data) {

    if(err) {

      res.writeHeader(404, "Not Found", {'Content-Type': 'text/html'});

      res.end('Not Found');

    } else {

      res.writeHeader(200, "OK", {'Content-Type': 'text/html'});

      res.end(data);

    }

  });

}

处理GET与POST请求提交的数据

  • 通过GET方法传递的数据可以使用url.parse(req.url).query获取到GET请求提交的数据,使用querystring内置模块(无需加载)来解析

  • GET请求提交的数据绑定在url中,使用querystring.parse()方法解析url的query属性便可以得到GET请求提交的数据

  • POST请求提交的数据在HTTP的Body中,服务器接收到的是数据流(因为POST请求提交的数据量较大,需要从缓冲区区读取chunk)

    • 利用request对象的data事件,触发回调函数接收所有提交的数据。可以将其拼接到一个字符串上

    • 接收完所有数据后触发end事件,此时才可以使用querystring.parse()解析接收到的所有数据

var http = require('http');

var url = require('url');

var fs = require('fs');

var querystring = require('querystring');


var server = http.createServer();


var htmlDir = __dirname + '/html/';   // 使用fs读取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 '/users':  // 用户页

      sendData(htmlDir + '/user.html', req, res);

      break;


    // 增加登录页面的路由

    case '/login':  // 用户页

      sendData(htmlDir + '/login.html', req, res);

      break;

    // 增加登录页面提交数据的处理

    case '/login/check':  // 用户页

      if(req.method.toUpperCase() === 'GET') {

        console.log(querystring.parse(urlStr.query));    // 使用querystring.parse()将传递的数据解析为一个对象

      }

      if(req.method.toUpperCase() === 'POST') {

        var str = '';   // 用来接收POST传递来的数据

        req.on('data', function (chunk) {

          str += chunk;

        })

        req.on('end', function () {

          console.log(querystring.parse(str));

        })

      }

      break;


    default :  // 不存在

      sendData(htmlDir + '/404.html', req, res);

      break;

  }

});


//  每次请求都读取静态页面,再输出。   fs.readFile()方法封装了fs.open()、fs.read()和fs.close()方法

function sendData(file, req, res) {

  fs.readFile(file, function (err, data) {

    if(err) {

      res.writeHeader(404, "Not Found", {'Content-Type': 'text/html'});

      res.end('Not Found');

    } else {

      res.writeHeader(200, "OK", {'Content-Type': 'text/html'});

      res.end(data);

    }

  });

}


server.listen(8080, 'localhost');

常识

  • http模块的服务器默认返回的数据类型是text/html

  • http模块中的http.STATUS_CODES属性包含所有的状态码及其描述信息


转自: https://segmentfault.com/a/1190000008648371

作者: Kyxy


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


==========阅读原文==========


推荐文章
硕士博士读书会  ·  为什么最近几天大家都在疯传这两张图?
7 年前
山西老乡俱乐部  ·  山西二人台《挂红灯》,好看!!!
7 年前
大叔爱吐槽  ·  "嘴上说不要,身体却很诚实"...当真?
7 年前