node-day2

(1)前言

  大纲:

    

 

  其他:

    

 

     详见Markdown标记语言 

 

(2)代码风格及封号详见下节

 

(3)初步实现Apache功能

  1、审查node进程

    

 

     Ctrl+C关闭node服务后,再次审查

    

 

     此时便没有了node进程

  2、Apache服务

Apache服务器软件---默认有一个www目录,所有存放在www目录中的资源都可以通过网址来浏览

    

     Apache默认功能,默认显示index.html

     如上所示,在c盘下新建app目录,里面新建多个文件,接下来想实现某个效果:类似于Apache,可以通过文件路径直接访问读取www下的文件,在网页内展示

     

 

     

 

     

  3、类似于Apache统一处理资源

     

     接续处理,完善读取

    

  4、实例验证如下

    ①在D盘下新建www目录

      

    ②放入相应文件

       

    ③ 编写代码实现功能

// 引入网络构建服务模块
var http = require('http')
// 引入fs文件系统模块
var fs = require('fs')

// 创建server服务器
var server = http.createServer()

var wwwDir = 'D:/www'
//接收请求,处理响应事件
server.on('request',function(req,res){
    var url = req.url
    var filePath = '/index.html'
    if(url !== '/'){
        filePath = url
    }
    fs.readFile(wwwDir+filePath,function(error,data){
        if(error){
            return res.end('404 Not Found')
        }
        res.end(data)
    })
})

// 启动服务器,监听端口
server.listen(3000,function(){
    console.log('服务器启动成功,端口号为3000...')
})

  此时,启动服务器后便可以通过设定好的路径去访问相应文件

  

 

   

        

   

   需求升级:要求有图形操作页面,如下所示

    

 

(4)Apache目录列表模板

首先需要了解Apache默认行为,即如果目录下有index.html,则显示该页面。如果没有则显示目录列表

  1、删除index.html文件。显示目录列表

  2、编写代码

    ①访问模板页面(模板页面代码可以直接复制过来,模板代码参加下篇文章)

    

    

 

     ②问题解决

    

 

     ③读取目录API

    

    ④具体渲染见下节(5)

代码及文件结构如下:

    

// 引入网络构建服务模块
var http = require('http')
// 引入fs文件系统模块
var fs = require('fs')

// 创建server服务器
var server = http.createServer()

var wwwDir = 'D:/www'
//接收请求,处理响应事件
server.on('request',function(req,res){
    var url = req.url
    fs.readFile('./template.html',function(error,data){
        if(error){
            return res.end('404 Not Found')
        }
        res.end(data)
    })
})

// 启动服务器,监听端口
server.listen(3000,function(){
    console.log('服务器启动成功,端口号为3000...')
})

此时启动服务器,便会查看到网页模板页面

 

(5)Apache目录列表渲染

    1、分析

接下来只需要将获取到的目录下的文件和文件名,替换到template.html即可

  2、读取文件目录

var fs = require('fs')
fs.readdir('D:/www',function(error,files){
    if(error){
        return console.log('目录不存在')
    }
    console.log(files)
})

  

  3、结合Apache目录渲染①

首先在模板里写入标记,后期替换

  4、结合Apache目录渲染②

 替换标记

 

 

验证如下:

  5、结合Apache目录渲染③

如何将文件名和目录名替换到template.html里
    1、在template.html中需要替换的位置预留一个特殊的标记(类似之前模板引擎的特殊标记)
    2、根据files生成需要的HTML内容

  第一步:预留位置存放特殊标记

    

  第二步:动态生成HTML内容

    

 

(6)浏览器使用模板引擎artTemplate

  1、安装

    在当前目录下安装模板引擎,会自动下载到新创建的node_modules文件夹下

    

 

 

     

artTemplate相关的依赖文件都会一起下载下来,所以下载完成后的目录会包含其他文件

    

 

 

     

  2、浏览器中使用模板引擎(注意:模板引擎不关心内容)

    

    模板引擎只关心{{}}八字符里面的内容,验证如下

    

  3、模板遍历语法

    

 

 

     

 

 

     注意:mustache八字胡语法

    

 

(7)node.js使用模板引擎artTemplate

  1、步骤

    

  2、node中引用第三方脚本库,不能使用script,而是使用require导入

    

  3、文档API

    这里注意,浏览器的语法在这里无效,没有script标签

    

浏览官方文档后的API:
    template.render('模板字符串',替换对象),验证如下

    

  4、替换HTML模板进行测试

j    

 

 

     

 

 

     

 

 

     这样便可以实现node使用模板引擎解析替换对应内容,但这样模板内容太多,过于累赘,所以一般是从外部读取

  5、外部引入HTML模板

    

 

 

     接下来使用fs文件系统模块读取文件

    

 

 

     

  6、最后修改之前文件,不再手动拼接字符串

接下来使用模板引擎解析替换HTML页面

    

 

 

     整体代码如下

// 引入网络构建服务模块
var http = require('http')
// 引入fs文件系统模块
var fs = require('fs')
//引入模板引擎
var template = require('art-template')

// 创建server服务器
var server = http.createServer()

var wwwDir = 'D:/www'
//接收请求,处理响应事件
server.on('request',function(req,res){
    var url = req.url
    fs.readFile('./template-web.html',function(error,data){
        if(error){
            res.setHeader('Content-Type','text/plain;charset=utf-8')
            return res.end('404 Not Found')
        }
        fs.readdir(wwwDir,function(error,files){
            if(error){
                return res.end('目录不存在')
            }
            /*使用模板引擎解析替换data里的模板字符串*/
            var htmlStr = template.render(data.toString(),{
                files:files,
                title:'网页标题'
            })
            /*发送解析替换过后的响应数据*/
            res.end(htmlStr)
        })
    })
})

// 启动服务器,监听端口
server.listen(3000,function(){
    console.log('服务器启动成功,端口号为3000...')
})
template-web.html代码如下:
<html dir="ltr" lang="zh" i18n-processed="">

<head>
  <meta charset="utf-8">
  <meta name="google" value="notranslate">
  
  <style>
    h1 {
      border-bottom: 1px solid #c0c0c0;
      margin-bottom: 10px;
      padding-bottom: 10px;
      white-space: nowrap;
    }

    table {
      border-collapse: collapse;
    }

    th {
      cursor: pointer;
    }

    td.detailsColumn {
      -webkit-padding-start: 2em;
      text-align: end;
      white-space: nowrap;
    }

    a.icon {
      -webkit-padding-start: 1.5em;
      text-decoration: none;
    }

    a.icon:hover {
      text-decoration: underline;
    }

    a.file {
      background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;
    }

    a.dir {
      background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;
    }

    a.up {
      background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;
    }

    html[dir=rtl] a {
      background-position-x: right;
    }

    #parentDirLinkBox {
      margin-bottom: 10px;
      padding-bottom: 10px;
    }

    #listingParsingErrorBox {
      border: 1px solid black;
      background: #fae691;
      padding: 10px;
      display: none;
    }
  </style>
  <title id="title">{{title}}</title>
</head>

<body>
  <div id="listingParsingErrorBox">糟糕!Google Chrome无法解读服务器所发送的数据。请
<a href="http://code.google.com/p/chromium/issues/entry">报告错误</a>,并附上<a href="LOCATION">原始列表</a>。</div> <h1 id="header">D:\www\ 的索引</h1> <div id="parentDirLinkBox" style="display:none"> <a id="parentDirLink" class="icon up"> <span id="parentDirText">[上级目录]</span> </a> </div> <table> <thead> <tr class="header" id="theader"> <th onclick="javascript:sortTable(0);">名称</th> <th class="detailsColumn" onclick="javascript:sortTable(1);"> 大小 </th> <th class="detailsColumn" onclick="javascript:sortTable(2);"> 修改日期 </th> </tr> </thead> <tbody id="tbody"> {{each files}} <tr> <td data-value="apple/"><a class="icon dir" href="#">{{$value}}/</a></td> <td class="detailsColumn" data-value="0"></td> <td class="detailsColumn" data-value="1509589967">2018/11/2 上午10:32:47</td> </tr> {{/each}} </tbody> </table> </body> </html>

  最终解析结果

  

 

    7、添加判断

目前为止,已经做到了服务器端渲染。
区别于之前的技术,在前端拿到数据,模板引擎解析替换,是浏览器做的。
注意:这里使用服务器端+模板引擎进行了渲染,最早之前模板引擎是后端技术

   

  8、

 

(8)客户端渲染+服务器端渲染

   1、客户端渲染

    

 

 

     所以一般会发两次请求,第一次请求页面字符串,第二次请求数据

  2、服务端渲染

    

 

 

     当然,ajax等异步请求也会用到,只是看具体应用场景

  3、如何判断网页是客户端渲染还是服务器渲染

查看网页源代码,如果源代码里有页面对应内容,则是服务端渲染。如果没有页面对应内容,则是客户端渲染

    ①查看网页源代码,发现里面有商品信息,所以这里是服务端渲染

      

 

       

    ②查看商品评价,明显有异步操作,没有刷新页面,但局部更新了页面部分内容,这里便使用了客户端渲染技术

      

 

       如果是客户端后期动态追加的,便从源码里找不到相应内容

  4、小结

分析后得出,商品列表为服务端渲染,在发送响应时,将页面和数据一起给了浏览器,可以在审查源代码里找到。
而商品评价为客户端渲染,是客户端发送请求,后期动态生成的,审查源代码找不到。
所以,一个网站既有服务端渲染,又有客户端渲染。

  5、SEO问题

之所以将客户端渲染和服务器渲染结合,这里主要考虑SEO搜索引擎优化问题。
ajax异步渲染的数据,使用爬虫无法获取,即客户端渲染不利于SEO

    

  6、使用场景

如果需要考虑SEO搜索引擎优化,则必须使用服务端渲染,否则使用客户端渲染可以更快一些,用户体验也更好

 

(9)【留言板案例】---处理网站里的静态资源

  需求:对之前文件做下完善,目录是目录样式,文件是文件样式,目录也可以点击进入,但这里已经对服务端渲染有了基本了解,所以接下来不再做处理

  接下来做个留言板案例

  1、启动服务简写

将创建服务和监听端口合并到一步,简写如下

    

  2、读取模板文件

为了让目录结构保持统一清晰,约定把所有的HTML文件都放到views目录中

    

  3、注意

    

    验证分析:

    

     

分析:之所有有这么多请求,首先,页面是一个请求,页面里的相关资源也是请求

    此时网站之所以一直卡着不动,是因为没有对静态资源做处理

    

 

 

  4、服务端处理静态资源

此时不可能一依次添加判断,为了统一处理这些静态资源,我们约定将所有静态资源都存放在public目录中。

       === >  

除此之外,还可以包含lib目录,用于存放第三方包

    

     

     此时再次启动服务器测试,请求成功

public目录已经开放开来,如果后期还用到静态资源,直接放到对应目录下即可。
这里将bootstrap放到lib目录下,然后修改引用路径

    

     app.js完整代码如下:

var http = require('http')
var fs = require('fs')

http.createServer(function(req,res){
    var url = req.url
    if(url === '/'){
        fs.readFile('./views/index.html',function(error,data){
            if(error){
                return res.end('404 Not Found.')
            }
            res.end(data)
        })
    }else if(url.indexOf('/public/' === 0)){
        fs.readFile('.' + url,function(error,data){
            if(error){
                return res.end('404 Not Found.')
            }
            res.end(data)
        })
    }
}).listen(3000,function(){
    console.log('服务启动完毕,3000端口访问... ...')
})

    此时便可以正确渲染了

    

   5、小结

public专门用于存放客户端静态资源
例如css、图片、js、jquery(服务端没有DOM,所以不可能用到jquery)

 

     客户端如果想用,引入即可

    

 

 

 

 

(10)页面跳转+404

   1、输入无效url时,跳转至404页面

    这里之所以不用设置请求头信息类型,因为在404.html已经设置了元标签meta标签

    

 

     

var http = require('http')
var fs = require('fs')

http.createServer(function(req,res){
    var url = req.url
    if(url === '/'){
        fs.readFile('./views/index.html',function(error,data){
            if(error){
                return res.end('401 Not Found.')
            }
            res.end(data)
        })
    }else if(url.indexOf('/public/')=== 0){
        fs.readFile('.' + url,function(error,data){
            if(error){
                return res.end('402 Not Found.')
            }
            res.end(data)
        })
    }else{
        fs.readFile('./views/404.html',function(error,data){
            if(error){
                return res.end('403 Not Found.')
            }
            res.end(data)
        })
    }
}).listen(3000,function(){
    console.log('服务启动完毕,3000端口访问... ...')
})

  2、发表留言页面跳转

     点击留言时,跳转至留言页面

    

 

     

 

(11)渲染评论首页

  1、首先在服务端写个数组,然后在模板页面进行遍历

      

 

       

 

       结果如下

    

  2、接下来在服务端使用模板引擎

核心模块为node自带,不用安装
第三方模块需要下载安装

    

    

    

 

     

(12)处理表单get提交

  1、表单提交行为

表单提交行为大概分为两种
    1、默认的提交行为(同步提交)
    2、异步提交

    

  2、点击后跳转到对应url

    

  3、url模块解析API

    将提交后的url进行解析,如下所示

    

 

     加入true参数,如下所示

    

url模块解析API
    url.parse(url链接)
    url.parse(url链接,true)

  4、注意

    

  5、url模块

    

  6、使用url模块

var http = require('http')
var fs = require('fs')
var template = require('art-template')
var url = require('url')

var comments = [
    {name:'tony',message:'你好tony,感觉人生达到了巅峰',data:'2016-02-12'},
    {name:'bob',message:'你好bob,感觉人生达到了巅峰',data:'2016-03-02'},
    {name:'jack',message:'你好jack,感觉人生达到了巅峰',data:'2016-11-18'}
]

http.createServer(function(req,res){
    var parseObj = url.parse(req.url,true)
    /*单独获取不包含查询字符串的路径部分,该路径不包含?之后的内容*/
    var pathname = parseObj.pathname
    if(pathname === '/'){
        fs.readFile('./views/index.html',function(error,data){
            if(error){
                return res.end('404 Not Found.')
            }
            var htmlStr = template.render(data.toString(),{
                comments:comments
            })
            res.end(htmlStr)
        })
    }else if(pathname.indexOf('/public/')=== 0){
        fs.readFile('.' + pathname,function(error,data){
            if(error){
                return res.end('404 Not Found.')
            }
            res.end(data)
        })
    }else if(pathname === '/post'){
        fs.readFile('./views/post.html',function(error,data){
            if(error){
                return res.end('404 Not Found.')
            }
            res.end(data)
        })
    }else if(pathname === '/pinglun'){
        /*这里不能再判断url,因为是动态的,所以只需要判断pathname即可*/
        res.end(JSON.stringify(parseObj.query))
    }else{
        fs.readFile('./views/404.html',function(error,data){
            if(error){
                return res.end('404 Not Found.')
            }
            res.end(data)
        })
    }
}).listen(3000,function(){
    console.log('服务启动完毕,3000端口访问... ...')
})

  

 

   

   现在已经收到数据,接下来开始进行下一步解析处理

  

 

 

(13)表单提交重定向

  接着上面的操作

   1、如何通过服务器让客户端重定向(服务器重定向)

    先写个死数据测试下

            如何通过服务器让客户端重定向? 
              1、设置状态码为302临时重定向(301为永久重定向)
              2、在响应头中通过Location告诉客户端网哪里重定向
              3、如果客户端发现收到的服务器响应状态码是302,就会自动去响应头中找Location然后对该地址发送新请求
              4、因此便可以看到客户端自动跳

    

else if(pathname === '/pinglun'){
        /*这里不能再判断url,因为是动态的,所以只需要判断pathname即可
        测试res.end(JSON.stringify(parseObj.query))
        */
        /*添加数据-注意:不是持久化存储,后期介绍*/
        var comment = parseObj.query
        comment.dateTime = '2017-11-3 12:12:30'
        comments.push(comment)
        /*重定向到首页*/
        /*
            如何通过服务器让客户端重定向? 
              1、设置状态码为302临时重定向(301为永久重定向)
              2、在响应头中通过Location告诉客户端网哪里重定向
              3、如果客户端发现收到的服务器响应状态码是302,就会自动去响应头中找Location然后对该地址发送新请求
              4、因此便可以看到客户端自动跳转
        */
        res.statusCode = 302
        res.setHeader('Location','/')
        res.end()/*结束响应*/
    }

    接下来做下测试,点击Network中的Preverse log保存重定向日志,然后提交数据

    

浏览器发现状态码为302,然后去请求头Header里找Location,再次对新路径发起请求,进行重定向跳转

      

  2、接下来即可通过本地局域网ip进行访问测试

    

 

     

 

(14)小结

  1、node底层

    

  2、步骤

    

  3、 接下来

    

 

 

 

 

 

 

 

.

posted @ 2020-01-02 20:01  剑仙6  阅读(219)  评论(0编辑  收藏  举报
欢迎访问个人网站www.qingchun.在线