【秒杀】前端网络-HTTP

你所浏览的网站基于网络,当前看到的网页也是基于网络,在前端中,网络几乎无处不在,哪怕代码里面没有和网络打交道,在使用、发布等过程中一定会用上网络。所以不管看不看得到,网络一定是前端里面重要的部分

概述

网络

网络,那涉及的知识可就太多了:五层网络模型,七层IO,TCP/IP,HTTP,缓存,SSL/TLS,HTTP2,Websocket,CSRF,XSS.....都属于网络的内容。本章主要对前端的HTTP进行讲解。

前端网络

对于新手前端或者大部分的码农来说,前端网络要用到的内容并不多,不过掌握网络的知识仍然是非常重要的,谁也不能保证以后遇到问题一定用不上某些知识。

在常见的前端程序里面,用到最多的技术是HTTP,例如你所浏览的网页,正是浏览器对某个地方发起了HTTP请求所得到的,至于这是个什么请求,可以打开一个网页,试着按下F12,打开网络面板

在这里,所有网络请求一览无余,我们来一点一点地看本章的内容-HTTP。

HTTP

HTTP,全称为Hypertext Transfer Protocol,超文本传输协议。听起来有点莫名其妙的对不对?这里的超文本可以认为就是“除了文本之外,还有更多种可能”的一种传输协议,比如图片,视频等等等等内容,不只是文本一种。它是一种客户端主动发起的请求,例如浏览器等客户端,意味着服务器是不能主动和我们连接的。

为了简化流程,我们假设现在只有客户端-服务器两端,省去代理、路由等内容。

假设客户端就是浏览器,服务器就是网站www.arsrna.com的服务器(假设,其实这个网站是serverless的)

我要获取到网站的内容,需要首先向服务器发起一个请求,然后服务器再将这个请求“回复”到客户端。仔细斟酌一下这句话,发起的请求是什么请求?

回到F12的网络面板,仔细看这个面板

上面说的发起的请求是什么请求就有答案了,是GET请求,请求的服务器地址是https://www.arsrna.com,服务器给我们了200的响应。

至于这里的标头和响应是什么意思,就要看HTTP的结构是什么样的了

HTTP请求结构

上述浏览器访问网站的过程,在HTTP中是这样的:

代码语言:http
复制
GET / HTTP/1.1
Host: www.arsrna.com
Accept-Language: zh
...更多的请求头

引用MDN的一张图,HTTP的结构如下:

  • Method 请求的方法,这部分是客户端与服务器进行协商的,常见的类型有GET,POST,PUT,DELETE。要注意这些方法不一定就只是这些方法,只是客户端和服务器认同的方法。你可以认为这些方法只是个名字,比如我喊班长来收作业,不一定只能喊班长,也可以直接喊他的名字,他也能正常回应我的要求。
  • Path 请求的路径,例如https://www.arsrna.com/app/render/,那Path就是/app/render/
  • Version 协议版本,当前常用的还是HTTP1.1版本
  • Headers 请求标头。包含有关要获取的资源或客户端或请求资源的客户端的更多信息,可参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers
  • Body 请求体。上图还有一部分没有提及,就是请求体,在GET协议中是不支持这部分信息的。Body信息要在Headers后面空一行

注意注意注意!!!你发送的所有请求不是由单方面决定的,不是服务器也不是客户端,而是两方共同决定的,服务器说是POST,客户端就必须是POST,而约定他们的,要看开发是怎么规定的,所以请求之前一定要看好请求的文档,不能按自己的想法来请求!!!

工具

如果你不知道如何测试http请求是否有效,可以用Visual Studio Code里面的REST Client插件,只需要新建.http后缀的文件,输入文本,点击上方的Send Request即可测试

举例

www.arsrna.com有一个接口来获取动态信息,我给你了一篇文档,内容如下:

  • 请求方法:GET
  • URL:https://api-gz.arsrna.cn/release/mainsite

请试着写出HTTP

代码语言:http
复制
GET /release/mainsite HTTP/1.1
Host: api-gz.arsrna.cn

测试一下,非常地200非常OK

HTTP响应结构

上文中我们已经对https://api-gz.arsrna.cn/release/mainsite发送了一个HTTP的GET请求,并且成功拿到了服务器返回来的数据。响应的结构跟请求的结构类似

同样地,响应部分跟请求部分类似,不过要注意的是,为了看起来方便,我把相应体格式化了,一般为了节省服务器流量,响应体一般都是压缩成一行且去空格的,当然不是说一定是一行,多行的响应体也是可以的。

前端发送HTTP

终于了解了HTTP了,来到代码的地方,前端发送HTTP可以通过AJAX的方法,要注意,AJAX不是某种库,而是一种技术。

AJAX

AJAX全称是异步js和xml,虽然叫做XML,但是用的时候还真不一定是XML。

在浏览器原生js中,实现AJAX可以使用fetch API或者XHR对象,要注意,一切网络请求都是异步的请求,意味着网络请求不会阻塞浏览器的渲染,可以放心请求。你可以理解为它在后台默默帮你完成请求。

注意,以下内容均在以浏览器为客户端,因为下述API在不同环境内核不一样,在nodejs中是以http.js为内核的,而浏览器则是原生api。

fetch

这里推荐使用fetch,在语法上更符合前端的质感,而且是浏览器原生的API。

一个示例:

代码语言:js
复制
fetch('https://api-gz.arsrna.cn/release/mainsite')
    .then(msg => msg.json())
    .then(msg => console.log(msg));

这段的作用就是 GET https://api-gz.arsrna.cn/release/mainsite然后打印到控制台

当然你不能直接在控制台使用这段代码,因为该地址有CORS保护,还有页面的Content Security Policy保护,这些在以后会说到。

这个就是请求成功后的结果,和上文HTTP请求的响应是一模一样的,只不过前端进行了格式化处理。

其实fetch还有很多参数,详见:https://developer.mozilla.org/zh-CN/docs/Web/API/fetch

不过我们平时用的只有一部分,大部分都已经默认好了。

这是一个POST请求示例:

代码语言:js
复制
fetch('http://myserver.com/path/to/post',{
    method:'post',
    headers:{'Content-Type':'application/json'}
    body:JSON.stringify({
        wives:['爱莉希雅','菲谢尔'],
        mostLike:'爱莉希雅'
    })
})
    .then(msg => msg.json())
    .then(msg => console.log(msg));

如果使用HTTP语法,是这样的:

代码语言:http
复制
POST /path/to/post HTTP/1.1
Host: myserver.com
Content-Type: application/json

{"wives":["爱莉希雅","菲谢尔"],"mostLike":"爱莉希雅"}

要注意,fetch里面的body我做了一个JSON.stringify的处理,目的是让js将对象转为字符串,否则服务器收到的是js的[Object object],这块涉及到js构造体的知识,这里不展开。以及Header部分,其实服务器收到的Header是不分大小写的,一定要注意,不然以后写后端代码的时候会跳坑!!!

XHR

有时,尤其是在旧的代码中,你会看到另一个名为 XMLHttpRequest(经常会被简写为“XHR”)的 API,它也用于发送 HTTP 请求。其早于 Fetch API,而且是第一个广泛用于实现 AJAX 的 API。如果可以,我们建议你使用 Fetch:它是一个更简单的 API,而且比 XMLHttpRequest 的特性更多。

这句话来自MDN,原生的XHR对象。

当然XHR的过时不意味着淘汰,fetch能取代XHR的绝大部分,而有一点是无法替代的,那就是获取请求进度,例如上传文件的时候,fetch就不能得知上传了多少,或者下载了多少,而XHR可以。

如果使用XHR,建议从第三方库入手,这样了解起来更简单,这里使用大名鼎鼎的axios,至于如何安装,请参考官方文档:https://www.axios-http.cn/docs/intro

为了更直观展示,下面的例子均用axios方法,而不是axios.对应方法来进行请求。

以上述fetch的实例,发送一个GET请求:

代码语言:js
复制
axios({
url:'https://api-gz.arsrna.cn/release/mainsite'
})
.then(msg => console.log(msg.data));

以上述fetch的示例,发送一个POST请求:

代码语言:js
复制
axios({
url:'http://myserver.com/path/to/post',
type:'post',
headers:{'Content-Type':'application/json'},
data:JSON.stringify({
wives:['爱莉希雅','菲谢尔'],
mostLike:'爱莉希雅'
})
}).then(msg=>{
console.log(msg.data);
})

用法跟fetch大差不差,如果fetch实现不了的部分是刚需,还是建议大家使用fetch,毕竟原生,可以少一次引用。

总结

到这里,关于在前端进行网络请求的内容就已经算是入门了,往后仍有更长的路要走,本章仅仅对HTTP进行讲解,以后还会遇到像上传文件,下载文件,跑通接口,跨域,认证,jwt token,session,登录注册,SSE(服务器主动发送事件),Websocket(服务器客户端双向通信)等等一系列更复杂的实战挑战,一切的前提,是学会HTTP。

没有网络,无法连接你我,你对我的文章发送了请求,我会用心写一篇文章并将文章返回给你