技术面‍:前端代码是如何与服务器交互的

前言: 本篇文章主要是想讲解 .html 文件和 .CSS 文件在实际开发中和后端服务器交互最后上线的基础原理。

面向的人群🆕:是刚入行不久,且目前只会写前端业务代码而不清楚整个工作流的前端新人。我会从 0 开始一步一步带你理解整个流程的底层逻辑是什么,希望你能跟着我一起做完今天的所有步骤。


一. 前期准备

  1. 为了能让更多的人明白这其中的原理,今天我们回归前端最原始的本质,抛开 VueReact 这些前端框架,只用最原始的 .js.css 文件开始今天的讲解。

  2. 你的电脑需要安装 node,因为会用到一些文件读写的操作。

  3. 创建一个文件夹,然后创建出下面两个文件,一个 index.html 文件和 server.js 文件。
    image.png

  4. index.html 文件如下,你也可以自己写喜欢的内容,但是如果懒得写,请 copy 我的代码

        <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><h1>JavaScript is the best language in the world!</h1></body>
    </html>
  5. 我相信每个前端开发的读者都,或多或少安装过下面这个插件 Live Server
    image.png
    实现的效果是将你编写的 .html文件直接在浏览器打开,可以帮我们极大提升开发体验,实现的效果如下图:
    1.gif

  6. 看起来很神奇对吧?其实 Live Server 实现的功能和我们今天要讲解的知识非常接近,让我们暂时先关闭它,然后准备实现一个自己的简易版 Live Server
    image.png

二. 什么是服务器

  1. 在此之前,我觉得很有必要先解释一下服务器这个概念,因为这个概念之前困扰我很久。

  2. 对于前端来讲,因为不像后端开发者一样需要日常跟服务器打交道,所以可能会觉得服务器是一个很高大上的东西,是一个我们前端开发人员触不可及的东西。包括我刚入行的时候,我也是这样想的,但随着工作阅历的不断增加,发现服务器是一个再普通不过的东西罢了。

  3. 我们从现实生活类比,服务器就好比一家超市。

    • 你去超市的目的是什么?
    • 答:购买日用品 ,那么此时你就是消费者,那么超市就是给你提供服务的地方对吧?在这种场景下,你充当的其实就是 客户端(client) 的角色,而超市就充当着服务器的角色。服务器并不一定只能提供单一的服务,就像超市提供了很多类型的柜台,有日用品,有肉类,有水果,这些不同的柜台充当着给你提供服务的角色,而超市是容纳这些服务运行的地方,这就是服务器服务之间的关系。

    2.jpeg

  4. 你还可以自己再类比所有日常生活中需要你花钱消费的地方。如饭店、宾馆、花店、网吧等等。它们都是为了满足你的需求,来为你提供这些需求的场所,它们都充当着 “服务器” 的角色。

  5. 让我们回到网络上面来,你完全可以把 “服务器” 和上面你类比现实世界所理解到的概念画等号。比如你今天想看视频,我们拿 B站举例, 那么B站 此时就是一个服务器,当你在地址栏输入 bilibili 后,你就相当于走进了 “视频分类” 柜台 ,它上面存放着各种各样的视频,B站 它现在提供了观看视频的一项服务给你。
    image.png

  6. 然后你看视频看累了,想看一看漫画,此时就变成了它提供 “漫画” 服务给你。
    image.png

  7. 还是有点抽象?让我们回到 Live Server。刚刚我们关闭了 Live Server,所以导致我们在浏览器里输入 localhost:5500 这个地址后,页面出现了访问错误。
    image.png

  8. 但是当我们打开 Live Server 的时候,我们发现页面又恢复了正常工作。
    3.gif

  9. 那么上面的步骤,我们就可以这样理解:

    • Live Server 运行的时候,我们的电脑给了我们一个可以使用浏览器访问本地 .html 文件的服务。这个服务的提供者就是 Live Server 这个程序。那么谁是服务器呢?没错,就是帮你运行 Live Server主机-----你的电脑

    • 当你关闭 Live Server 的时候,相当于你的电脑关闭了提供服务的程序,导致你失去了访问 .html 的能力。

  10. 通过上面的例子,不难发现,其实服务本质上是一段代码,而运行这段代码的容器被我们叫做了服务器

  11. 这里有一个十分重要的概念----端口号。也就是 Live Server 启动的 5500 这个数字。这个数字你可以暂时把它理解为,你的电脑(也就是服务器)给它找了一个唯一的服务窗口,这个窗口号是 5500。(想象一个政务大厅,里面不同的业务都开设在不同的窗口位置,即使此时没人访问,它也需要有工作人员坐在那里等待。)
    image.png

  12. 那么上面整个过程可以这样理解:

    • 😣 Live Server: “好烦,周一又要上班了。喂,服务器(你的电脑),5500 这个窗口还没人值班吧?没人的话我就先坐这了。”

    • 🧑‍🏫 你的电脑:“我看一下啊,哦,暂时没人用。那你坐这里吧,即使没人来,你也不能跑出去啊!”

  13. 聪明的你也许会想到,那如果 5500 窗口如果有人先占了怎么办?注意,这里服务器你的电脑)会自动安排你的程序到另外的端口号上提供服务(执行代码)。(如果你的程序中也支持这么做的话,不妨打开两个 vscode 自己尝试一下同时开启 live Server 看看会是什么效果。)

三. 编写 server.js 文件

  1. 既然我们已经知道了,服务其实就是一段代码。那么我们就可以根据需求,去编写出这样的代码。其实我们的需求很简单,就是想让我的浏览器可以正常渲染我的 .html 文件。

  2. 这里我们需要从 node 中引入 http 模块,这个模块封装了一些可以让我们快速编写 http 服务器的方法。
    image.png

  3. 注意:这里我说了编写 “http 服务” 这个概念,结合我们上面对服务器的理解。这句话的完整含义应该是:

    node 提供的 http 模块,让我们可以快速在电脑上,编写一段代码程序。当我们的电脑运行这段程序的时候,我们的电脑可以提供 http 这样一项服务,此时浏览器可以通过使用 http 协议来和这个 http 服务程序进行通信。

  4. 然后我们调用 http 模块提供的 createServer 方法,具体用法在注释中写的很清楚了,不过多赘述。
    image.png

  5. 现在的你已经创建出了一个服务实例,它虽然还没有任何功能,但你已经可以告诉你的电脑,它现在可以被当作一个服务程序启动了。那么此时你还需要告诉电脑你想在那个窗口(端口) 去提供服务,这里我随便写了一个 7777,你可以选择一个任意你喜欢的数字。(注意,有些端口号是操作系统独享的,你不能占用,最好使用 5000-65535 范围内的数字) 然后使用 http_server.listen() 方法去向电脑申请这个端口号
    image.png

  6. 让我们在 http_server 的回调函数中,打印一些数据,来看看我们的服务是正常启动了。
    image.png

  7. 让我们在终端用 node 运行这个文件,你可以在控制台看到你的这段代码已经被你的电脑成功启动了。
    7.gif

  8. 可以看到,随着我用浏览器去访问这个在窗口 7777 提供的服务,我们回调函数监听到请求后成功打印了相对应的输出。

  9. 但是此时我们的浏览器好像呆呆的,没有展示任何信息。这是因为你这项服务现在还不够到位,你没有返回给浏览器任何信息。此时我们需要调去 response 身上的 end 函数。response.end()。这个函数第一个参数是你要告诉浏览器的数据,第二个参数也是一个回调函数,会在你返回给浏览器消息后被调用。那么我们就可以这样写:
    (这里别忘了需要 ctrl c,然后重新执行这个文件)
    image.png

  10. 你会看到虽然我们的服务成功打印了相应的输出,但是我们浏览器显示的却是乱码
    image.png
    image.png

  11. 这是因为你没告诉浏览器应该用什么格式去渲染这段数据,你可能会有疑问,浏览器这么笨吗?默认为 utf-8 不就行了?如果你能联想到这里,不得不给你点个赞👍,但是假如这段数据是图片视频呢,那不就乱套了吗?这里不卖关子,解决方法很简单,就是我们的服务在返回数据之前,告诉浏览器该如何展示我们的内容,怎么告诉?调用 response.writeHeader()设置相对应的 Content-type 即可。
    image.png
    现在的显示效果就符合我们的预期啦!
    image.png

四. 读取 html 文件

  1. 这里涉及到 node 的一些知识,不过不是本篇文章的重点,故不会做过多解释。

  2. 这里有两个重点,第一个就是引入 fs文件系统模块,它提供了一个方法叫做 readFileSync,这个函数是同步读取指定路径下的文件,默认返回值为 buffer 类型。
    image.png

  3. 当拿到这个 data 后,我们就可以返回给浏览器这个数据。此时你的浏览器应该已经正确渲染出这些内容了。
    image.png

五. CSS 文件生效的原理

  1. 让我们在跟文件夹下生成一个 global.css 的文件。
    image.png

  2. 别忘了我们最初是如何引入 cssindex.html 的。
    image.png

  3. 这里有一个关键的知识点需要了解,我们打开 localhost:7777,其实是会向我们的服务发起三个请求的。其中,发送 index.html 是我们的主动行为,favicon.ico 这个请求是浏览器的默认行为,global.css 是由于我们的 index.html 携带了 \<link/> 标签,从而引起浏览器附带请求导致的。
    image.png

  4. 让我们打印一下 requesturl 参数信息,这里包含了浏览器请求资源的地址。
    image.png
    它对应了浏览器 request 字段的信息。
    image.png

  5. 刷新一下浏览器,你会看到控制台有以下三个输出,和我们上面的推测是符合的。注意,这里的根路径 / 路径之后会被我们替换为 index.html
    image.png

  6. 聪明的你可能已经发现了,我们浏览器其实已经请求了 global.css 但是样式好像没有正确的生效。那是因为 .css 文件没有设置正确的 mime 格式。被浏览器当成普通的文件格式处理了。
    image.png

  7. 这里我们就需要为 index.html.css 分别设置不同的 content-type 来让 css 文件生效。此时你的 http_server 的代码应该如下。

      const http_server = http.createServer((request, response) => {let file_path = ""; //1. 这里存放文件的真实路径let data = ""; //2. 这里准备存放文件的 buffer 数据let ext = ""; //3. 这里准存放文件的后缀名称if (request.url === "/") { //4. 如果请求路径是跟路径,那么替换为 index.htmlfile_path = "index.html";} else {file_path = request.url.replace("/", ""); //5. 否则的话,去掉路径前面的斜杠 '\'}data = fs.readFileSync(file_path);
    }  
    
  8. 这里最关键的后缀名如何获取呢?我们需要引入另一个模块 path。我们利用 path.extname 方法,将切割好的 file_path 传递为参数即可获取到正确的文件后缀名。
    image.png

  9. 之后为每次请求设置正确的类型即可。具体文件类型 mimecontent-type 的映射关系请参照:MDN提供的 MIME 对照表。
    image.png

  10. 此时我们可以看到,样式已经正确生效。
    image.png

六. 80 端口的含义

  1. 想必大家都知道 http 服务是跑在 80 端口这一前端常识的吧?其实它没什么特别的,它只不过是把端口申请在服务器的80窗口上而已,然后我们配合浏览器的默认行为—当没有指定明确端口号时,帮你自动填写为 80 端口。

  2. 我们来试验一下。
    image.png
    注意,此时我没有像之前一样输入 7777,但是浏览器却依然正确找到了我http-服务的位置,和我们对浏览器默认行为的猜想一致。
    33.gif

  3. 所以不要再死记硬背 80443 这两个数字了,它们只不过是你的后端搭档在代码程序里根据业务不同而写下的一个普通数字罢了。

  4. 为什么要这样做?如果每个 http-server 开发者,大家都用不同的端口号。那么你就需要不仅仅需要把它们的域名记下来,还要记住相对应的端口号。就像上面一样,你不觉得每次手动输入 7777 很麻烦吗?那么干脆大家和浏览器商量好,就用 80 这个端口,浏览器默认帮你填写就好了。

七. 源码

这里故意屏蔽了 favicon.ico 的请求,和文章整体内容关系不大。

const http = require("node:http"); //从 node 中引入 http 模块
const fs = require("node:fs"); //引入 fs 模块
const path = require("node:path");// 这个函数接收一个回调函数
// 1.第一个函数接收的是前端传递过来的 request 参数
// 2.第二个函数是要返回给浏览器的信息const http_server = http.createServer((request, response) => {let file_path = ""; //1. 这里存放文件的真实路径let data = ""; //2. 这里准备存放文件的 buffer 数据let ext = ""; //3. 这里准存放文件的后缀名称if (request.url === "/") {//4. 如果请求路径是跟路径,那么替换为 index.htmlfile_path = "index.html";} else {file_path = request.url.replace("/", ""); //5. 否则的话,去掉路径前面的斜杠 '\'}if (file_path !== "favicon.ico") {response.writeHeader = `Content-type:text/${ext}`;data = fs.readFileSync(file_path);ext = path.extname(file_path);}response.end(data);
});// 告诉你的电脑,你想用 7777 这个端口
http_server.listen("7777", () => {console.log("我提供的服务在 7777 窗口");
});

八. 总结

  1. 首先我们要对服务器有清晰的认知,任何一个设备都可以当作一个服务器,你的手机,你的笔记本,你的台式机,一个大型的存储计算机,都可以被叫做服务器。

  2. 所谓的服务就是跑在服务器上的一段普通代码程序而已。当代码运行起来后,服务器需要为这个服务分配一个唯一端口号,其它应用可以访问这个端口来接受你提供的服务。

  3. 有些服务并不是要公开为别人使用的,查看你的任务管理器或活动监视器。你的电脑开启了这么多服务,它们占用着不同的端口,而这些服务有的是只为操作系统提供的,并不对普通用户提供任何服务。
    image.png

  4. 我们的前端代码,不管是 .vue.tsx.ts 等等文件,最后都会被打包为原始的 htmlcssjs 文件,因为浏览器只认识这些内容。(不信你去看看有 content-type: vue 这种 mime 类型吗?)然后后端会部署一个 http-server 程序,让它跑在一个专属服务器上执行这段程序,通过我们上面讲解的内容来传递给 80 或者其他任何端口上,等待别人访问。

  5. 你在实际开发中使用的 npm run dev 后,你的前端代码呈现在浏览器上,其底层的原理和上面无异,不过是开发工具帮你将上面步骤封装的功能更加完善和便捷而已。
    image.png

  6. 本文中对于 server.js 对创建服务器的流程做了最大化的精简,来确保读者能够适应服务这个概念。在实际开发中,公司真正的后端服务开发绝不是这么简单。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

当HR问你是否单身时,该怎么回答?

知识星球&#xff08;星球名&#xff1a;芯片制造与封测技术社区&#xff0c;星球号&#xff1a;63559049&#xff09;里的学员问&#xff1a;我是晶圆厂厂务工程师&#xff0c;最近在面试新工作&#xff0c;但是几乎每家HR都会问我同一个问题&#xff1a;你结婚没有&#xff1…

短剧平台开发中的常见误区及避坑指南,别再走弯路

1. 误区一&#xff1a;只注重外观&#xff0c;忽视技术基础 在短剧平台开发中&#xff0c;一个常见的误区是过于注重产品的外观设计&#xff0c;而忽视了技术基础的重要性。团队往往会投入大量精力和资源来打造吸引人的UI和炫酷的特效&#xff0c;但忽略了系统架构、性能优化和…

听说京东618裁员?所以日常准备很重要呀

文末有最少必要的面试题&#xff0c;还准备了离线 PDF 版本。 京东也要向市场输送人才了? 这几天看到技术群里不少朋友在讨论京东裁员相关的信息。 我去看了下京东近期的操作&#xff0c;京东内部考勤调整和午休时间缩短&#xff0c;以及强化打卡机制等管理调整&#xff1b;有…

腾讯Java社招面试题真题,最新面试题

Java中synchronized和ReentrantLock有什么区别&#xff1f; 1、锁的实现方式不同&#xff1a; synchronized是JVM层面的锁&#xff0c;主要依赖于监视器对象&#xff08;monitor&#xff09;实现。ReentrantLock是JDK层面的锁&#xff0c;通过Java代码实现&#xff0c;提供了更…

echarts- 热力图, k线图,雷达图

热力图 热力图可以看成是一种矩形的散点图。 热力图的矩形受itemStyle的影响。 通常配合visualmap组件来根据值的大小做颜色的变化。 热力图主要通过颜色去表现数值的大小&#xff0c;必须要配合 visualMap 组件使用。 visualMap:视觉映射组件 let options {tooltip: {},xAx…

Kali的基本扫描命令

nmap -sP 192.168.10.0/24 //扫描10网段存活的主机 nmap -P 192.168.10.142 //扫描主机开放的端口 nmap -sS 192.168.10.142 //TCP半开扫描 nmap -sT 192.168.10.142 //TCP全开扫描 nmap -O 192.168.10.142 //扫描靶机的操作系统类型 nmap -sV 192.168.10.142 //扫描开放端口对…

使用Prometheus组件node_exporter采集linux系统的指标数据(包括cpu/内存/磁盘/网络)

一、背景 Linux系统的基本指标包括cpu、内存、磁盘、网络等&#xff0c;其中网络可以细分为带宽进出口流量、连接数和tcp监控等。 本文使用Prometheus组件node_exporter采集&#xff0c;存储在promethues&#xff0c;展示在grafana面板。 二、安装node_exporter 1、下载至本…

Bean 的生命周期的各个阶段

Bean的生命周期通常可以归结为以下几个阶段&#xff1a; 1.实例化&#xff08;Instantiation&#xff09;&#xff1a; Spring根据Bean的定义&#xff08;如XML配置、Java配置或注解&#xff09;来实例化Bean&#xff0c;这个阶段会分配内存空间给Bean&#xff0c;生成一个原始…

微服务:Ribbon负载均衡与加载时机修改

Ribbon 负载均衡 执行流程 负载均衡策略 调整负载均衡方案&#xff1a; 配置类中&#xff08;全局&#xff09;&#xff1a; // 负载均衡策略Beanpublic IRule randomRule() {return new RandomRule();}yaml配置 userservice: # 给某个微服务配置负载均衡规则&#xff…

Mac 安装 git

文章目录 前言一、介绍二、下载三、验证四、配置五、Git常用命令六、git提交和撤销工作流程代码提交和提交同步代码撤销和撤销同步 FAQ1.homebrew 下载解决方法一&#xff08;强烈推荐&#xff09;&#xff1a;解决方法二&#xff1a; 总结 前言 Git 是一个开源的分布式版本控…

Fastadmin框架使用phpstudy部署,部分页面404无法显示

背景 在windows系统下&#xff0c;使用phpstudy部署fastadmin框架&#xff0c;会部分页面404无法访问。 解决方案 原来是要用伪静态&#xff0c;自己看官方视频时喜欢跳着看&#xff0c;刚好漏了&#xff0c;这里记录下。 依次点击如下&#xff1a; 如果你是Apache&#xf…

使用libtorch加载YOLOv8生成的torchscript文件进行目标检测

在网上下载了60多幅包含西瓜和冬瓜的图像组成melon数据集&#xff0c;使用 LabelMe 工具进行标注&#xff0c;然后使用 labelme2yolov8 脚本将json文件转换成YOLOv8支持的.txt文件&#xff0c;并自动生成YOLOv8支持的目录结构&#xff0c;包括melon.yaml文件&#xff0c;其内容…

【C语言】自定义类型:联合与枚举的简明概述

&#x1f525;引言 关于自定义类型除了我们常用的结构体&#xff0c;还有联合与枚举也是属于自定义类型。本篇将简单介绍联合与枚举基本概念和使用方法 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&…

etcd 和 MongoDB 的混沌(故障注入)测试方法

最近在对一些自建的数据库 driver/client 基础库的健壮性做混沌&#xff08;故障&#xff09;测试, 去验证了解业务的故障处理机制和恢复时长. 主要涉及到了 MongoDB 和 etcd 这两个基础组件. 本文会介绍下相关的测试方法. MongoDB 中的故障测试 MongoDB 是比较世界上热门的文…

php部分特性漏洞学习

php部分函数漏洞学习 简单总结一些我遇到的ctf中的php的一些函数或特性的漏洞&#xff0c;我刷题还是太少了&#xff0c;所以很多例子来自ctfshow&#xff0c;以后遇到相关赛题再更新 1.MD5和其他hash 弱类型比较 php中&#xff0c;有两中判断相等的符号&#xff0c;和&…

c# 贪心算法(Greedy Algo)

贪婪是一种算法范式&#xff0c;它逐步构建解决方案&#xff0c;始终选择提供最明显和直接收益的下一个部分。贪婪算法用于解决优化问题。 如果问题具有以下属性&#xff0c;则可以使用贪心法解决优化问题&#xff1a; 每一步&#xff0c;我们都可以做出当前看来最好的选择&…

HTML-JavaWeb

目录 1.标题排版 2.标题样式 ​编辑 ​编辑 小结 3.超链接 4.正文排版 ​编辑​编辑​编辑5.正文布局 6.表格标签 7.表单标签 8.表单项标签 1.标题排版 ● 图片标签 :< img> src:指定图像的ur1(绝对路径/相对路径) width:图像的宽度(像素/相对于父元素的百…

月薪5万是怎样谈的?

知识星球&#xff08;星球名&#xff1a;芯片制造与封测技术社区&#xff0c;星球号&#xff1a;63559049&#xff09;里的学员问&#xff1a;目前是晶圆厂的PE&#xff0c;但是想跳槽谈了几次薪水&#xff0c;都没法有大幅度的增长&#xff0c;该怎么办&#xff1f;“学得文武…

感知觉训练:解锁独立生活的钥匙

在日新月异的科技时代&#xff0c;一款名为“蝙蝠避障”的辅助软件以其独到之处&#xff0c;为盲人朋友的日常生活平添了诸多便利&#xff0c;不仅实现了实时避障&#xff0c;还通过拍照识别功能扩展了信息获取的边界。然而&#xff0c;科技辅助之外&#xff0c;提升盲人朋友的…

低代码的原理、发展历史、使用场景和优势。

在数字化转型的浪潮中&#xff0c;低代码开发平台&#xff08;YDUIbuilder&#xff09;以其独特的优势迅速崛起&#xff0c;为各行各业带来了创新的解决方案。本文将深入探讨低代码的原理、发展历史、使用场景以及它所带来的优势。 gitee下载&#xff1a;yduibuilder: 快速开发…