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

前言: 本篇文章主要是想讲解 .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.html
        file_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.html
    file_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 对创建服务器的流程做了最大化的精简,来确保读者能够适应服务这个概念。在实际开发中,公司真正的后端服务开发绝不是这么简单。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes(k8s) v1.30.1 本地集群部署 安装metallb 支持LoadBalancer 生产环境 推荐 BGP模式部署

1 metallb 安装参考:Kubernetes(k8s) v1.30.1 本地集群部署 默认不支持LoadBalancer metallb来解决-CSDN博客 2 删除 Layer 2 模式 配置 kubectl delete -f IPAddressPool.yaml kubectl delete -f L2Advertisement.yaml kubectl delete -f discuz-srv.yaml 3 配置 k8s Metal…

2024电工杯数学建模B题完整论文讲解(含每一问python代码+数据)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024电工杯数学建模B题大学生平衡膳食食谱的优化设计及评价完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 …

【Python】 XGBoost模型的使用案例及原理解析

原谅把你带走的雨天 在渐渐模糊的窗前 每个人最后都要说再见 原谅被你带走的永远 微笑着容易过一天 也许是我已经 老了一点 那些日子你会不会舍不得 思念就像关不紧的门 空气里有幸福的灰尘 否则为何闭上眼睛的时候 又全都想起了 谁都别说 让我一个人躲一躲 你的承诺 我竟然没怀…

SQL使用函数给多个分表添加同一字段

数据库中分表时&#xff0c;往往需要向多个分表中添加同一个字段&#xff0c;可以定义一个函数&#xff0c;每次调用这个函数向多个份表中添加同意字段。 1、创建函数示例&#xff1a; 在PostgreSQL中创建一个简单的函数 以下是一个在PostgreSQL中创建函数的简单示例&#x…

Mac安装 Intellij IDEA,亲测有效M1、M2可用

引言 最近开始学习使用spring boot写一个简单的后端项目&#xff0c;使用Intellij IDEA软件&#xff0c;Intellij IDEA为新用户提供了30天的免费试用。 方案 1.官网下载Intellij IDEA IntelliJ IDEA – the Leading Java and Kotlin IDE 或者直接网盘连接下载&#xff1a;…

OrangePi AIpro开箱评测

开箱评测 有幸受邀参与了CSDN与OrangePi组织的评测活动&#xff0c;今天刚收到快递。拆开快递能看到保护盒、电源、双头typec线这三样&#xff08;充电器和线有保护膜的我先拆掉了&#xff09; 打开保护盒&#xff0c;能看到上下两块黑色海棉包裹的开发板&#xff08;保护得不…

三、Servlet基础

注&#xff1a;因为我并不完全是为了从0开始Java开发&#xff0c;因此&#xff0c;我这里先暂时跳过第二章服务器环境相关的内容&#xff0c;直接开始第三章的内容。 3.1、Servlet 的基本结构&#xff1a; ​ 下面的代码给出了一个基本的 Servlet &#xff0c;它处理 GET 请求…

QtXlsx库编译使用

文章目录 一、前言二、Windows编译使用2.1 用法①&#xff1a;QtXlsx作为Qt的附加模块2.1.1 检验是否安装Perl2.1.2 下载并解压QtXlsx源码2.1.3 MinGW 64-bit安装模块2.1.4 测试 2.2 用法②&#xff1a;直接使用源码 三、Linus编译使用3.1、安装Qt5开发软件包&#xff1a;qtbas…

翻译《The Old New Thing》- Why are INI files deprecated in favor of the registry?

Why are INI files deprecated in favor of the registry? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071126-00/?p24383 Raymond Chen 2007年11月26日 为什么弃用 INI 文件而改用注册表&#xff1f; 欢迎&#xff0c;Slashdot的读…

【再探】设计模式—职责链模式、命令模式及迭代器模式

行为型设计模式研究系统在运行时对象之间的交互&#xff0c;进一步明确对象的职责。有职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式及访问模式共11种。 1 职责链模式 需求&#xff1a;1) 请求能被多…

2024可信赖的企业级生成式 AI 白皮书

来源&#xff1a;COPU&IBM&#xff1a; 近期历史回顾&#xff1a;

[随笔] 在CSDN的6周年纪念日随笔

纪念 转眼已过6年&#xff0c;大一的时候学习编程&#xff0c;潜水 CSDN 学习各类博文&#xff0c;才学浅薄就没有主动写博文记录自己的学习历程。 过了段时间刚刚到了大二&#xff0c;很喜欢 Todolist&#xff0c;意气风发的写下《一份清爽的编程计划》&#xff0c;哈哈。 …

新浪测试社招要个25K,第一次面大厂挂了

一面 1、讲下被测系统和你负责测试的模块功能&#xff1f; 2、为什么选择这个测试框架&#xff0c;这个测试框架有什么优缺点&#xff1f; 3、测试文件的目录&#xff0c;包含哪些包&#xff0c;这些之间是怎么调用的&#xff1f; 4、UI自动化和接口自动化都是怎么做的&…

FFmpeg之转码

文章目录 概述transcode小结 概述 上一篇说了主要的流程&#xff0c;也就是ffmpeg_parse_options的流程&#xff0c;如下图&#xff1a; 红色箭头的流程说的差不多了&#xff0c;接下来看看绿色框框&#xff0c;也就是transcode的流程。 transcode 还是先给出我画的流程图&…

SPSS之因子分析

SPSS中因子分析功能在【分析】--【降维】--【因子分析】中完成&#xff08;在SPSS软件中&#xff0c;主成分分析与因子分析均在【因子分析】模块中完成&#xff09;。 因子分析的求解通常从分析原始变量的协方差矩阵或相关矩阵着手。 &#xff08;1&#xff09;当变量取值的度…

纯CSS丝滑边框线条动画

在这个网站&#xff08;minimal-portfolio-swart.vercel.app&#xff09;发现一个不错的交互效果&#xff0c;用户体验效果很不错。如封面图所示&#xff0c;这个卡片上有一根白色的线条围绕着卡片移动&#xff0c;且在线条的卡片内部跟随这一块模糊阴影&#xff0c;特别是在线…

无线麦克风哪个品牌音质最好,揭示麦克风什么牌子的音质效果好!

​随着科技的不断发展&#xff0c;无线领夹麦克风已经成为现代演讲、演出和采访中不可或缺的工具。这种小巧便携的设备&#xff0c;能够让我们摆脱线缆的束缚&#xff0c;自由地在舞台上或讲台上移动&#xff0c;同时保持声音的清晰和稳定。在这篇文章中&#xff0c;我们将介绍…

国产操作系统上telnet命令详解 _ 统信 _ 麒麟 _ 中科方德

原文链接&#xff1a;国产操作系统上telnet命令详解 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产操作系统上使用telnet命令的详细介绍文章。telnet是一个经典的网络协议和工具&#xff0c;广泛用于测试和管理远程服务器。本文将详…

低代码与人工智能:改变软件开发的未来

引言 在当今快速发展的科技时代&#xff0c;软件开发行业也在不断地创新和演进。其中&#xff0c;低代码开发和人工智能技术是两个备受关注的领域&#xff0c;低代码开发通过简化开发流程和降低编码难度&#xff0c;使得软件开发变得更加高效和便捷&#xff0c;而人工智能技术…

收放卷主从轴速度随动增益计算(CODESYS ST代码)

收放卷主从轴速度随动控制,我们需要知道随动增益,如果是利用电子齿轮实现速度随动,我们需要通过增益计算电子齿轮比的分子和分母,具体源代码大家可以参考下面文章链接: 收放卷伺服控制系统详细算法介绍(电子齿轮+张力PID卷绕轴控制功能块)_收放卷伺服控制属于-CSDN博客文…