node.js 学习笔记(二)模板引擎和C/S渲染

文章目录

  • node.js 学习笔记(二)模板引擎和C/S渲染
  • 一、初步实现Apache功能
    • 1.1 使用模板引擎
    • 1.2 在 node 中使用模板引擎
  • 二、客户端渲染和服务器渲染
    • 2.1 客户端渲染
      • 1. 客户端(浏览器)渲染过程
      • 2. 要点
      • 3. 优缺点
    • 2.2 服务器渲染
      • 1. 要点
      • 2. 优缺点
    • 2.3 实际开发情况
  • 三、处理网站的静态资源
  • 四、重定向
    • 4.1 临时重定向和永久重定向

一、初步实现Apache功能

Apache 服务器软件默认有一个 www 目录,所有存放在 www 目录中的资源都可以通过地址来访问,如下:

127.0.0.1:80/a.txt

127.0.0.1:80/index.html

127.0.0.1:80/apple/login.html

let http = require('http');
let fs = require('fs');let server = http.createServer();let wwwDir = 'C:/Users/frontEnd/node/www';server.on('request',function(req,res) {let url = req.url;let filePath = '/index.html';if (url !== '/') {filePath = url;}fs.readFile(wwwDir + filePath, function(err, data) {if (err) {return res.end('404 Not Found.');} else {res.end(data);}})
})server.listen(3000,function() {console.log("服务器启动成功");
});

1.1 使用模板引擎

问题:

  1. 如何得到 wwwDir 目录列表中的文件名和目录名?

    解决方案:fs.readdir

  2. 如何将得到的文件名和目录名替换到 template.html 中?

    解决方案1:模板引擎

    解决方案2:

    1. 在 template.html 中需要替换的位置预留一个特殊的标记
    2. 根据 files 动态生成需要的 html 内容
<!-- template.html -->
<html dir="ltr" lang="zh">
<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 {padding-inline-start: 2em;text-align: end;white-space: nowrap;}a.icon {padding-inline-start: 1.5em;text-decoration: none;user-select: auto;}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">C:\Users\frontEnd\node\www\ 的索引</title></head>
<body><div id="listingParsingErrorBox">糟糕!Google Chrome无法解读服务器所发送的数据。请<ahref="http://code.google.com/p/chromium/issues/entry">报告错误</a>,并附上<a href="LOCATION">原始列表</a></div><h1 id="header">C:\Users\frontEnd\node\www\ 的索引</h1><div id="parentDirLinkBox" style="display: block;"><a id="parentDirLink" class="icon up" href="/C:/Users/%E5%B0%8F%E8%90%8C/Desktop/Ability/frontEnd/node/www/.."><span id="parentDirText">[上级目录]</span></a></div><table><thead><tr class="header" id="theader"><th id="nameColumnHeader" tabindex="0" role="button">名称</th><th id="sizeColumnHeader" class="detailsColumn" tabindex="0" role="button">大小</th><th id="dateColumnHeader" class="detailsColumn" tabindex="0" role="button">修改日期</th></tr></thead><tbody id="tbody">^_^</tbody></table>
</body>
</html>
let http = require('http');
let fs = require('fs');let server = http.createServer();let wwwDir = 'C:/Users/frontEnd/node/www';server.on('request',function(req,res) {let url = req.url;fs.readFile('./template.html', function(err, data) {if (err) return res.end('404 Not Found.');fs.readdir(wwwDir, function(err, files) {if(err) return res.end('Can not find wwwDir.');var content = '';files.forEach(function (item) {// 在 ES6 中的 ``(反引号)字符串中可以使用 ${} 来引用变量content += `<tr><td data-value="apple/"><a class="icon dir"href="/C:/Users/%E5%B0%8F%E8%90%8C/Desktop/Ability/frontEnd/node/www/apple/">${item}/</a></td><td class="detailsColumn" data-value="0"></td><td class="detailsColumn" data-value="1635659913">2021/10/31 下午1:58:33</td></tr>` })data = data.toString(); // 转换为字符串data = data.replace('^_^', content);res.end(data); //发送解析替换完的内容})})
})server.listen(3000,function() {console.log("服务器启动成功");
});

可以用模板引擎优化,将 html 放入另一个文件template-apache.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title id='title'>{{ title }}</title>
</head>
<body><table><thead><tr class="header" id="theader"><th id="nameColumnHeader" tabindex="0" role="button">名称</th><th id="sizeColumnHeader" class="detailsColumn" tabindex="0" role="button">大小</th><th id="dateColumnHeader" class="detailsColumn" tabindex="0" role="button">修改日期</th></tr></thead><tbody id="tbody">{{each filesName}}<tr><td data-value="apple/"><a class="icon dir"href="/C:/Users/%E5%B0%8F%E8%90%8C/Desktop/Ability/frontEnd/node/www/apple/">{{$value}}/</a></td><td class="detailsColumn" data-value="0"></td><td class="detailsColumn" data-value="1635659913">2021/10/31 下午1:58:33</td></tr>{{/each}}</tbody></table>
</body>
</html>
let http = require('http');
let fs = require('fs');
let template = require('art-template');let server = http.createServer();let wwwDir = 'C:/UsersfrontEnd/node/www';server.on('request',function(req,res) {let url = req.url;fs.readFile('./template-apache.html', function(err, data) {if (err) return res.end('404 Not Found.');fs.readdir(wwwDir, function(err, files) {if(err) return res.end('Can not find wwwDir.');let htmlStr = template.render(data.toString(), {title: 'hhhhh',filesName: files})res.end(htmlStr); //发送解析替换完的内容})})
})server.listen(3000,function() {console.log("服务器启动成功");
});

1.2 在 node 中使用模板引擎

使用 art-template 模板引擎,模板引擎不关心模板内容,只关心能够识别的模板标记语法,如 {{ }}(在浏览器中)

使用步骤:

  1. 安装 npm install art-template --save

  2. 在需要使用的文件模块中使用 require 加载 art-template,参数 art-template 就是下载包的名字

  3. 查文档,使用模板引擎API

    template.render('模板字符串','替换对象')
    //例子如下:
    template.render('hello {{ name }}', {name: 'Jack'
    })
    
<!-- tpl.html -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><p>大家好,我叫: {{ name }}</p><p>我今年 {{ age }} 岁了</p><p>我来自 {{ province }}</p><p>我喜欢: {{each hobbies}} {{ $value }} {{/each}}</p>
</body>
</html>
let template = require('art-template');
let fs = require('fs');fs.readFile('./tpl.html',function(err, data) {if(err) return console.log('读取文件失败');// data 默认是二进制数据,而模板引擎需要接收字符串var res = template.render(data.toString(), {name: 'Jack',age: 18,province: '重庆市',hobbies: ['写代码','听音乐','街舞']})console.log(res); // 结果如下图
})

二、客户端渲染和服务器渲染

2.1 客户端渲染

1. 客户端(浏览器)渲染过程

  1. 浏览器向服务器请求页面
  2. 接收服务器响应的页面字符串
  3. 浏览器从上往下依次解析,在解析过程中,若发现 ajax 请求,则再次发起请求
  4. 浏览器向服务器请求数据
  5. 接收 ajax 响应结果
  6. 模板引擎渲染

2. 要点

  • 浏览器至少向服务器发送两次请求:
    ① 第一次请求页面
    ② 第二次请求动态数据
  • 在浏览器查看源代码中看不到数据,数据时客户端渲染动态追加的
  • 执行类似分页的功能时不会重新渲染页面
  • 客户端异步渲染是很难被爬虫抓取到的,就很难定位信息,如:在购买商品时就搜索不到商品信息

3. 优缺点

优点:

  • 能够尽早地看见页面

缺点:

  • 数据量大时,加载渲染缓慢,会看见页面中部分空白

  • 客户端渲染不利于 SEO 搜索引擎优化

2.2 服务器渲染

1. 要点

  • 客户端接收的是已经渲染了数据的页面

  • 服务器渲染只需要浏览器请求一次

  • 能够在浏览器查看源代码时能够看到数据

  • 执行类似分页的功能时会重新渲染页面

  • 服务器渲染可以被爬虫抓取

2. 优缺点

优点:

  • 返回地就是最后结果,客户端不需要再做任何处理,所以也不会看见空白页面
  • 渲染加载页面速度更快
  • 利于 SEO 搜索引擎优化

缺点:

  • 服务器压力增大

2.3 实际开发情况

实际的网站中既不是纯异步的客户端渲染也不是纯服务器渲染的,而是两者结合,例如:京东的网站中商品列表采用服务端渲染,目的为了 SEO 搜索引擎优化,而商品评论列表为了用户体验(加载速度更快),而又不需要 SEO ,所以采用客户端渲染

三、处理网站的静态资源

背景:浏览器收到 HTML 响应内容后,从上往下开始解析,在解析过程中,如果发现 link、script、img、iframe、video、audio 等带有 src 或者 href(link)属性标签(具有外链资源)时,浏览器会自动对这些资源发起新的请求,导致网页加载渲染很缓慢。为了方便的统一处理静态资源,约定所有的静态资源都存放在 public 目录中。如果请求路径是以 /public/ 开头的,则认为要获取 public 中的某个资源,就直接可以把请求路径当作文件路径来读取

整个 public 目录中的资源都允许访问

let http = require('http');
let fs = require('fs');http.createServer(function (req, res) {let url = req.url;if (url === '/') {fs.readFile('./views/index.html', function (err, data) {if (err) {return res.end('404 Not Found');}res.end(data);})} else if (url === '/post') {fs.readFile('./views/post.html', function (err, data) {if (err) {return res.end('404 Not Found.');}res.end(data);})} else if (url.indexOf('/public/') === 0) {fs.readFile('.' + url, function (err, data) {if (err) {return res.end('404 Not Found.');}res.end(data);});} else {fs.readFile('./views/404.html', function (err, data) {if (err) {return res.end('404 Not Found.');}res.end(data);})}}).listen(3000, function () {console.log('服务器已经启动');})

四、重定向

如何通过服务器让客户端重定向?

解决方法:

  1. 状态码设置为302(临时重定向):statusCode
  2. 在响应头中通过 Location 告诉客户端往哪儿重定向:setHeader
  3. 若客户端发现收到的服务器的状态码时 302 ,就会自动去响应头中找 Location,然后对该地址发起新的请求,就能看到客户端跳转了

4.1 临时重定向和永久重定向

  • 永久重定向(301)

    • 新网址完全继承旧网址,旧网址的排名等完全清零。

    • 301重定向是网页更改地址后对搜索引擎友好的最好方法,只要不是暂时搬移的情况,都建议使用301来做转址。

  • 临时重定向(302)

    • 对旧网址没有影响,但新网址不会有排名

    • 抓取新的内容的时候,保留旧的地址,因为当前的重定向只是暂时的,很快就会恢复旧地址的访问。

举例:

例如:我们之前网站的域名是 a.com,现在替换成了 b.com。但是用户并不知道域名改了,所以还是在浏览器里输入 a.com,Web服务器(apache 或者 ngnix)在收到请求后,在响应中包含:

  • 状态码 301 及 b.com。用户的浏览器在收到响应后,**自动将输入栏网址改变为 b.com。**不会请求 a.com
  • 或者状态码 302 及 b.com。用户的浏览器在收到响应后,输入栏仍是显示旧网址,但是显示的是 b.com的内容。会请求 a.com

node.js 学习笔记(二)模板引擎和C/S渲染相关推荐

  1. node.js学习笔记(二):核心

    NodeJS核心东西随着版本更新越来越多,详情看官方文档:http://nodejs.org/api/  下面简单介绍几个用的比较多的  1.全局对象 在浏览器JavaScript 中,通常windo ...

  2. node.js学习笔记

    # node.js学习笔记标签(空格分隔): node.js---## 一 内置模块学习 ### 1. http 模块 ``` //1 导入http模块 const http =require('ht ...

  3. node.js学习笔记5——核心模块1

    node.js学习笔记5--核心模块1 Node.js核心模块主要内容包括:(1)全局对象 (2)常用工具 (3)事件机制 (4)文件系统访问 (5)HTTP服务器与客户端 一: 全局对象 Node. ...

  4. 唤醒手腕 - 前端服务器端开发 Node.Js 学习笔记(学习中,更新中)

    唤醒手腕 - Node.Js 学习笔记 唤醒手腕个人的学习记录,时间在2021年12月13日 ~ 2021年12月14日,学习方式看官方文档和B站视频,如有错误或者代码问题的地方,欢迎C站大佬能够帮忙 ...

  5. node.js学习笔记14—微型社交网站

    node.js学习笔记14-微型社交网站 1.功能分析 微博是以用户为中心,因此需要有注册和登录功能. 微博最核心的功能是信息的发表,这个功能包括许多方面,包括:数据库访问,前端显示等. 一个完整的微 ...

  6. Node.js学习笔记8

    Node.js学习笔记8 HTTP服务器与客户端 Node.js的http模块,封装了一个高效的HTTP服务器和一个简易的HTTP客户端 http.server是一个基于事件的HTTP服务器,核心由N ...

  7. 千锋Node.js学习笔记

    千锋Node.js学习笔记 文章目录 千锋Node.js学习笔记 写在前面 1. 认识Node.js 2. NVM 3. NPM 4. NRM 5. NPX 6. 模块/包与CommonJS 7. 常 ...

  8. Vue.js 学习笔记 二,一些输出指令

    Vue的一些输出指令 {{字段}},v-text指令,v-html指令 <html> <head><meta name="viewport" cont ...

  9. 【学习笔记】Node.js学习笔记(二)

    三.使用Node.js进行Web开发 1.安装Express Express是官方推荐的Web开发框架,功能十分强大. 在命令行输入 npm install -g express 进行全局安装Expr ...

最新文章

  1. Metro中文件夹和文件的创建
  2. TF之LSTM:利用基于顺序的LSTM回归算法对DIY数据集sin曲线(蓝虚)预测cos(红实)(matplotlib动态演示)—daiding
  3. Web技术电子期刊2008年第3期(总第23期)
  4. condition可数吗 living_单词辨析 知识讲解 condition situation state的区别
  5. saiku docker配置部署_【安装教程】01 Gitea Docker 安装部署 - 【SkywenCode】技术团队基...
  6. 【技术+某度面经】Jenkins 内容+百度面经分享
  7. linux awk
  8. 欠拟合和过拟合的一般解决方法
  9. Pytorch和caffe对maxpool模式ceil比较
  10. IntelliJ IDEA设置鼠标悬浮提示
  11. vc2010c语言,VC2010下载_VisualC++2010官方下载「vc2010」-太平洋下载中心
  12. Silverlight载入动画(简易)
  13. 小葵花妈妈课堂开课了《RecyclerView 复用解析》
  14. poco http使用
  15. router跳转外部链接
  16. jquery 前端实现图片压缩和上传
  17. 线段树染色问题(例题为poj2777)
  18. 线性回归中的最小二乘法和梯度下降法比较
  19. Frenetic Python实验(三)
  20. [立创传智黑马程序员CSDN]训练营——仿生机械狗

热门文章

  1. java aa 咖啡怎样冲泡_越南滴漏咖啡冲泡方法
  2. 济南市社区应急救援站:科技预警+快速救援体系
  3. 85页智慧楼宇建设解决方案
  4. java-net-php-python-jspm设备维修保养计划管理系统计算机毕业设计程序
  5. LUOGU P2920 [USACO08NOV]时间管理Time Management
  6. 蓝牙耳机哪个品牌好?国产蓝牙耳机排行榜揭晓
  7. 基于51单片机的PT100热敏电阻数字温度计-仿真设计
  8. MicroPython实现ESP8266 控制电子墨水屏(SPI)
  9. 【小李木耳】推荐:《换一种方式飞行》
  10. python3时间格式化