Web前端高级工程师培训:使用 Node.js 构建一个 Web 服务端程序(3)

news2024/10/23 8:02:21

11、HTTP 协议

11-1、协议的定义

HTTP 是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web 上进行数据交换的基础,是一种 client-server 协议,也就是说,请求通常是由像浏览器这样的接受方发起的。一个完整的Web文档通常是由不同的子文档拼接而成的,像是文本、布局描述、图片、视频、脚本等等。(来源:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview)。

无论是客户端请求还是服务端响应,本质就是在交换数据。因为交换的数据的多样性,为了能够让双方正确的理解和处理交换的数据,就需要给这些数据定义一些交换的方式和格式,这就是 HTTP 协议的基本作用。

一些参考资料:

  • https://tools.ietf.org/html/rfc2616

11-2、报文

报文 可以理解为交换的数据,在 HTTP 协议中规定了交换的格式,报文分为:

  • 请求报文
  • 响应报文
请求报文

在这里插入图片描述

响应报文

在这里插入图片描述

HTTP Headers

HTTP Headers 允许客户端和服务端在请求和响应的时候携带一些附加信息,客户端会根据不同的头信息字段和对应内容做出不同的操作。根据不同的上下文环境,HTTP Headers 可分为:

  • General Headers : 普通头,同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。
    • 参考:https://developer.mozilla.org/en-US/docs/Glossary/General_header
  • Request Headers : 请求头,包含更多有关要获取的资源或客户端本身信息的消息头。
    • 参考:https://developer.mozilla.org/en-US/docs/Glossary/Request_header
  • Response Headers : 包含有关响应的补充信息,如其位置或服务器本身(名称和版本等)的消息头。
    • 参考:https://developer.mozilla.org/en-US/docs/Glossary/Response_header
  • Entity Headers : 包含有关实体主体的更多信息,比如主体长(Content-Length)度或其MIME类型。
    • 参考:https://developer.mozilla.org/en-US/docs/Glossary/Entity_header

参考:https://tools.ietf.org/html/rfc4229#section-2.1.32

12、不同类型资源的处理

无论是请求还是响应,都会涉及到各种不同类型的资源要进行处理。为了能够让接收方(注:请求的接收方是服务端、响应的接收方是客户端)知道当前接收到内容类型,以便针对该类型进行对应的处理,所以需要在发送正文数据的同时需要同时告知该正文内容的类型格式。

12-1、使用 content-type 响应头返回资源类型

Content-Type 用于说明请求或相应中正文内容的 MIME 类型。

12-2、MIME 的作用与使用

MIME(Multipurpose Internet Mail Extensions) : 是一种用来表示 文档、文字或字节流的性质和格式的标准。

结构

MIME 的通用结构为 : type/subtypetype 为大类,subtype 为小类,如:text/htmltext/cssimage/png 等。

参考:https://www.iana.org/assignments/media-types/media-types.xhtml

12-3、设置响应头

使用 http 模块提供的 setHeader 方法就可以向响应中设置对应的头信息。

// #C12-3-1
...
server.on('request', (req, res) => {
  res.setHeader('Content-Type', 'text/html;charset="utf-8"');
});
...

13、动态资源

许多时候,服务端还可能会提供一些动态处理的资源,比如会根据当前时间,当前客户端访问用户的身份权限等条件进行一些逻辑处理后返回对应的资源,这个时候,针对同一个 URL 的请求可能会产生不一样的结果,这种资源我们可以成为:动态资源

13-1、使用 URL 路由表优化动态资源处理

因为动态资源的特性,资源并不能像静态资源一样简单的存储在一个外部文件中,然后使用一个 URL 与之关联。所以,针对这种资源,通常情况下,我们需要对不同的 URL 进行不同的处理。

  • 把不同的 URL 对应的一些逻辑分别保存(通常是函数)。
  • 准备一个路由表(可以使用对象格式进行存储,key是 URL,value是对应的函数)。
  • 根据当前访问的 URL ,找到路由表中的对应的函数并执行。
// #C13-1-1
...
// 路由表
const routesMap = new Map();
routesMap.set('/', async (req, res) => {
  res.setHeader('Content-Type', 'text/html;charset="utf-8"');
  res.end('首页');
});
routesMap.set('/list', async (req, res) => {
  res.setHeader('Content-Type', 'text/html;charset="utf-8"');
  res.end('列表');
});

server.on('request', async (req, res) => {
  ...
  const urlObj = new URL(req.url);
  ...
  
  const pathname = urlObj.pathname;
  
  // 根据当前的 pathname 指定 routeMap 中对应的函数
  let routeHandler = routesMap.get(pathname);
  if (routeHandler) {
      await routeHandler(req, res);
  }
});
...

13-2、URL 重定向

我们通过一个 重定向 的需求应用场景来加深一下关于协议(如 http 头)等相关知识的理解

需求 : 访问不存在的 URL ,重新定向到 / 路由。

13-2-1、HTTP 状态码

我们通常在访问出现一些问题的时候返回一个友好的页面(或数据)给客户端,但是客户端仅仅从页面(数据)本身是无法知道这个页面(或数据)是这次请求本身应该对应的数据,还是我们给他的一个错误提示,这个时候就可以在响应的同时返回一个称为:状态码 的内容给客户端,它由一组具有特定含义的数字组成:

  • 信息响应(100199)
  • 成功响应(200299)
  • 重定向(300399)
  • 客户端错误(400499)
  • 服务器错误 (500599)

注:虽然服务端可以随意返回指定的状态码,但是我们应当按照实际的情况返回标准中定义好的状态码。

参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status

参考:https://tools.ietf.org/html/rfc2616#section-10

// #C13-2-1-1
...
// 路由表
...

server.on('request', async (req, res) => {
  ...
  const urlObj = new URL(req.url);
  ...
  
  const pathname = urlObj.pathname;
  
  // 根据当前的 pathname 指定 routeMap 中对应的函数
  let routeHandler = routesMap.get(pathname);
  if (routeHandler) {
      await routeHandler(req, res);
  } else {
    // 告知客户端你应该重新发送请求,新的请求地址在 Location 头中。
    res.statusCode = 302;
    res.setHeader('Location', '/');
    res.end();
  }
});
...

13-3、404 Not Found

404 也是我们经常听到的一个词,它其实就是状态码中的一种

404 : 请求失败,请求所希望得到的资源未被在服务器上发现。

// #C13-3-1
...
// 路由表
...

server.on('request', async (req, res) => {
  ...
  const urlObj = new URL(req.url);
  ...
  
  const pathname = urlObj.pathname;
  
  // 根据当前的 pathname 指定 routeMap 中对应的函数
  let routeHandler = routesMap.get(pathname);
  if (routeHandler) {
      await routeHandler(req, res);
  } else {
    // 返回一个404的状态码与提示页面
    res.statusCode = 404;
    res.end('<h1>页面丢失了</h1>');
  }
});
...

14、后端渲染

14-1、数据与视图

除了一些静态文件数据以外,服务端还会通过诸如:数据库程序运算 等各种方式产生数据,同时我们又需要把这些数据通过页面(HTML,CSS)的方式进行组织(也就是试图)返回给客户端。

// #C14-1-1
...

let users = [
  {id: 1, username: '大海'},
  {id: 2, username: '子鼠'},
  {id: 3, username: '小蕊'},
];

// 路由表
const routesMap = new Map();
routesMap.set('/', async (req, res) => {
  res.setHeader('Content-Type', 'text/html;charset="utf-8"');
  res.end(`
      <ul>
        ${users.map(u => {
          return `<li>${u.username}</li>`
        }).join('')}
      </ul>
  `);
});
...

server.on('request', async (req, res) => {
  ...
});
...

14-2、数据与视图分离

如果视图内容直接写在后端程序中,后端程序不好维护,且前端不好配合。

我们可以把前端相关的内容提取到外部文件中,在利用 Node.jsfs 模块进行文件读取,并进行一些简单的替换。

// #C14-2-1
...
const fs = require('fs');

// 数据
...

// 路由表
const routesMap = new Map();
routesMap.set('/', async (req, res) => {
  res.setHeader('Content-Type', 'text/html;charset="utf-8"');
  let userListHtml = users.map(u => {
          return `<li>${u.username}</li>`
        }).join('');
  res.end( fs.readFileSync('./template/index.html').toString().replace(/${users}/gi, userListHtml) );
});
...

server.on('request', async (req, res) => {
  ...
});
...

./template/index.html

// #C14-2-2
...
<ul>${users}</ul>
...

模板 : 未被处理过的原始文件(如这里的:./template/index.html)。

视图 : 通过模板与数据和逻辑的处理生成的最终内容。

14-3、使用模板引擎优化渲染

以上的模板数据解析替换方式太简单,复杂一些的视图逻辑就不太方便了。这个时候我们就可以使用一些 模板引擎(功能更加强大的模板解析替换库) 来完成解析工作。

14-3-1、基于 JavaScript 的常用模板引擎
  • ejs
  • artTemplate
  • Nunjucks
14-3-2、Nunjucks

参考:http://mozilla.github.io/nunjucks/

15、案例:基于 Node.js 构建一个商城应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2221439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【解决】使用Hypermark将Markdown文件转化为HTML文件

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 文章目录 一、文件准备&#xff08;一&#xff09;HTML模板文件&#xff08;二&#xff09;MD文件夹和储存文件夹 二、文件转…

【C++贪心】1536. 排布二进制网格的最少交换次数|1880

本文涉及知识点 C贪心 决策包容性 LeetCode1536. 排布二进制网格的最少交换次数 给你一个 n x n 的二进制网格 grid&#xff0c;每一次操作中&#xff0c;你可以选择网格的 相邻两行 进行交换。 一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。 请你返回使网格满…

QUIC 启动!

掘金地址&#xff1a;https://juejin.cn/post/7428200842229006377 引言 QUIC是什么&#xff1f;明明你每天都在用&#xff0c;明明每天都在timing&#xff0c;难道你不知道吗&#xff1f;啊&#xff1f;不会吧&#xff0c;不会吧。 那就让本文来让你全方位的了解这个协议。 …

word表格跨页后自动生成的顶部横线【去除方法】

Hello World! Its been a long time. 这一年重心放在了科研、做事、追寻新的经历上&#xff0c;事有正事、琐事、幸事、哀事&#xff0c;内心与认知成长了一些&#xff0c;思想成熟了几分&#xff0c;技艺也有若干收获。不管怎样&#xff0c;来打个卡吧&#xff0c;纪念一下&…

爬虫日常实战

爬取美团新闻信息&#xff0c;此处采用两种方法实现&#xff1a; 注意点&#xff1a;因为此处的数据都是动态数据&#xff0c;所以一定要考虑好向下滑动数据包会更新的情况&#xff0c;不然就只能读取当前页即第一页数据&#xff0c;方法一通过更新ajax数据包网址页数&#xf…

【MyBatis】初识MyBatis 构建简单框架

目录 MyBatis前言搭建一个简单的MyBatis创建Maven项目引入必要依赖创建数据表结构创建User实体类创建Mapper接口Mapper层Dao层 创建MyBatis的Mapper映射文件编写测试类传统测试类JUnit测试 MyBatis 介绍&#xff1a;MyBatis是一款半自动的ORM持久层框架&#xff0c;具有较高的…

利用自定义 ref 实现函数防抖

今天来简单介绍一个新的方法&#xff0c;使用自定义 ref 实现函数防抖。 1. 自定义 ref 的来源 自定义 ref 防抖函数来自于前端开发中的两个概念&#xff1a;Vue 的响应式系统 和 数防抖&#xff08;Debounce&#xff09;。 1、Vue 响应式系统&#xff1a;Vue 提供了 ref 和…

Python学习的自我理解和想法(20)

#1024程序员节|征文# 学的是b站的课程&#xff08;千锋教育&#xff09;&#xff0c;跟老师写程序&#xff0c;不是自创的代码&#xff01; 今天是学Python的第20天&#xff0c;学的内容是面向对象中的私有属性&#xff0c;私有方法&#xff0c;多态&#xff0c;单例计模式。开…

【ubuntu18.04】ubuntu18.04升级cmake-3.29.8及还原系统自带cmake操作说明

参考链接 cmake升级、更新&#xff08;ubuntu18.04&#xff09;-CSDN博客 升级cmake操作说明 下载链接 Download CMake 下载版本 下载软件包 cmake-3.30.3-linux-x86_64.tar.gz 拷贝软件包到虚拟机 cp /var/run/vmblock-fuse/blockdir/jrY8KS/cmake-3.29.8-linux-x86_64…

spring源码中的,函数式接口,注解@FunctionalInterface

调用方 /org/springframework/beans/factory/support/AbstractBeanFactory.java:333sharedInstance getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It mi…

高级的SQL查询技巧有哪些?

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于高级SQL查询技巧方面的相关内容&#xf…

MATLAB人脸考勤系统

MATLAB人脸考勤系统课题介绍 该课题为基于MATLAB平台的人脸识别系统。传统的人脸识别都是直接人头的比对&#xff0c;现实意义不大&#xff0c;没有一定的新意。该课题识别原理为&#xff1a;先采集待识别人员的人脸&#xff0c;进行训练&#xff0c;得到人脸特征值。测试的时…

HomeAssistant自定义组件学习-【一】

#环境准备# 按官方的步骤准备就可以&#xff0c;我是在Windows下使用VS Code开发的&#xff0c;安装了WSL&#xff08;使用模板创建组件需要在WSL环境下完成&#xff09; 官方链接&#xff1a;https://developers.home-assistant.io/docs/development_environment 环境准备好…

力扣困难题汇总(14道)

题4&#xff08;困难&#xff09;&#xff1a; 思路&#xff1a; 找两数组中位数&#xff0c;这个看起来简单&#xff0c;顺手反应就是数第(mn)/2个&#xff0c;这个难在要求时间复杂度为log(mn)&#xff0c;所以不能这样搞&#xff0c;我的思路是&#xff1a;每次切割长度为较…

【K8s】Kubernetes 词汇表

微思网络 厦门微思网络 K8S认证工程师&#xff08;CKA&#xff09;备考与学习指南https://mp.weixin.qq.com/s/XsEVpU7dKnJDBopynWW3GQ K8S-CKA课程试听:Container 概述 词汇表 此术语表旨在提供 Kubernetes 术语的完整、标准列表。其中包含特定于 Kubernetes 的技术术语以及…

uniapp修改input中placeholder样式

Uniapp官方提供了两种修改的属性方法&#xff0c;但经过测试&#xff0c;只有 placeholder-class 属性能够生效 <input placeholder"请输入手机验证码" placeholder-class"input-placeholder"/><!-- css --> <style lang"scss" s…

redis的zset实现下滑滚动分页查询思路

常规zset查询 我们redis的数据为 我们知道 我们常规查询的话 我们假如 zset 表中 有7个元素&#xff0c;然后我们进行分页查询的话&#xff0c;我们一次查3个元素&#xff0c;然后查出来元素 和元素的分数 我们redis的语法应该这样写 zrevrangebyscore wang 1000 0 withsc…

kotlin实现viewpager

说明:kotlin tablayout viewpager adapter实现滑动界面 效果图 step1: package com.example.flushfragmentdemoimport androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.…

【uni-app学习-2】

一、跳转 方法&#xff1a;在methods中去定义方法&#xff1a; 上述为直接跳转&#xff0c;但是当你要跳转页面是由多个可切换页面组成比如&#xff1a; 这个页面其实是由两个页面组成&#xff0c;一个主页&#xff0c;一个我的&#xff0c;两个页面 路由配置需要用到toob…

java--多态(详解)

目录 一、概念二、多态实现的条件三、向上转型和向下转型3.1 向上转型3.2 向下转型 四、重写和重载五、理解多态5.1练习&#xff1a;5.2避免在构造方法中调用重写的方法&#xff1a; 欢迎来到权权的博客~欢迎大家对我的博客提出指导这是我的博客主页&#xff1a;点击 一、概念…