飞道的博客

浏览器中的网络请求

645人阅读  评论(0)

浏览器中的网络请求

第一次写于: 2020年3月29日

最近, 学习了一些网络知识; 所以就想着结合实际用到的内容, 写一篇文章;

ajax

我们使用HTTP协议用于和server端的数据交互;
其中最常用的方式就是 ajax

它的定义和好处无需多言; 网上很多, 不再赘述;
有很多文章讲的都是框架之上的使用, 屏蔽了原生内容;
我就想着稍微地了解一些具体浏览器是怎么操作的;
这里给大家做一个分享;

ajax 其实是对 HTTP 协议的封装;
它会发起一个HTTP请求, 在请求的状态改变(readyState)时, 执行我们传入的方法;

发起请求

ajax 在浏览器中通过内置的 XMLHttpRequest 来生成;

let httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
    if (httpRequest.readyState === XMLHttpRequest.DONE) {
        // Everything is good, the response was received.
    } else {
        // Not ready yet.
    }
};
// 请求方法 请求URL 是否异步
httpRequest.open('GET', 'http://www.example.org/some.file', true);
// 在send之前; open之后
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send("name=value&anothername=" + encodeURIComponent('哈哈哈') + "&so=on");

我们可以看到代码中的操作

  1. 打开一个请求 指定请求方法,请求URL,是否异步
  2. 设置请求头 这一步需要在 在send之前,open之后
  3. 发送数据 数据可以是字符串也可以是二进制数据

请求参数编码

GET

httpRequest.send("name=value&anothername=" + encodeURIComponent('哈哈哈') + "&so=on");

我们可以注意到这行代码中 encodeURIComponent 方法;
我们应该对参数名和参数值进行编码; 这样可以避免一些参数传递时的问题;

我们为啥要对参数进行编码呢?

  1. GET 请求方式中, 我们的参数都编码到URL上了;
  2. URL 中是不能出现中文和一些特殊符号的
  3. 我们需要传入一些中文和特殊符号

我们可以想象一下, 如果没有对参数编码会有啥后果;

  • 中文是肯定不能传入了
  • 如果value是 123&a=b 这种, 它会不会变成 123 和 a=b ?

为了避免这些编码上不必要的麻烦; 我们因此会对参数名, 参数值进行编码;
当然, 也有对应的解码的方法 decodeURIComponent

let plainText = 'h&123=12'
let encodedText = encodeURIComponent(plainText)
let decodedText = decodeURIComponent(encodedText)

POST

当我们发送一个 POST 请求时, 我们需要设置一个请求header的 Content-Type
用于说明, 我们请求的数据是哪种格式的.

POST常见的提交数据的格式有

  • application/x-www-form-urlencoded 效果和GET请求编码一样; 但是数据是放在请求体中的;
  • multipart/form-data 用于传输大数据; 有 boundary 进行数据分割;
  • application/json RESTful API 接口最常用的数据格式;
  • text/xml xml

POST请求处理请求数据, 它是把数据放在 请求体 中的;
但是, 这不代表POST请求中URL就不能编码了;
其实, 还是可以加入额外的参数的; 但是一般情况下, 还是遵守约定俗成的规范;

接受请求

之前, 提到了我们可以根据 readyState 来判断这个请求的状态;
那么有哪些状态呢?

  • UNSENT 0 (uninitialized) or (request not initialized)
  • OPENED 1 (loading) or (server connection established)
  • HEADERS_RECEIVED 2 (loaded) or (request received)
  • LOADING 3 (interactive) or (processing request)
  • DONE 4 (complete) or (request finished and response is ready)
let httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
    if (httpRequest.readyState === XMLHttpRequest.DONE) {
        // Everything is good, the response was received.
    } else {
        // Not ready yet.
    }

    if (httpRequest.status === 200) {
        var response = JSON.parse(httpRequest.responseText);
        // Perfect!
    } else {
        // There was a problem with the request.
        // For example, the response may have a 404 (Not Found)
        // or 500 (Internal Server Error) response code.
    }
};

接下来我们运行一下代码试试;

如果我们直接在文件夹中打开html文件;
那么, 我们会在地址栏中出现类似下面的情况

file:///C:/Users/ju/Desktop/ajax/test.html

这种情况下, 我们发送不了数据的;

打开devTool 我们会看到下面的报错信息

Access to XMLHttpRequest at ‘http://www.example.org/some.file’ from origin ‘null’ has been blocked by
CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

这就是著名的浏览器跨域请求问题;
解决 跨域 有很多方法;

跨域

跨域 是因为浏览器的同源策略导致的;

  1. 为啥要有跨域呢?

  2. 为啥浏览器要这么做呢?

  3. 跨域提供了最基础的安全;

  4. 防止别人恶意的请求;

默认情况下,JavaScript在发送 ajax 请求时,URL的域名端口号必须和当前页面完全一致。
否则, 就会报跨域的异常;

那么常见的解决方案有啥啊?

  1. JSONP 但是现在用的少了; 利用了浏览器中 一些标签没有跨域限制;
  2. NGINX 代理; 做一个静态资源文件的代理;
  3. 后端修改请求头, 设置 Access-Control-Allow-Origin
  4. 开发时 利用 webpack-dev-server (内部是用的http-proxy-middleware)

websocket

websocket 最近才刚刚接触;
只是做了一个小小的demo;

这里就不敢胡诌了; 简单谈一些;

为什么要有 websocket

首先要知道, 浏览器是主动发送请求给服务器的;
但是, 反过来, 服务器是不能主动给浏览器发送请求的;

那么, 在没有 websocket 之前, 我们处理 浏览器和服务器之间的通信;
只能采用 轮询 的方式;

所谓 轮询 就是每个一段时间访问一下服务器;
看看有没有啥新的消息;

例如在线聊天: 每个client 都发送给server消息;
但是呢, server接受到消息之后, 并不能直接把消息返给其它client;

而只能等client 轮询的时间到了, 再去把消息返回;

那么, 面对用户比较多, 而且对数据的实时性要求比较高;
例如, 视频会议等; 那么轮询就显得不行了;

websocket 有啥好处

websocket的出现, 就是解决了这一部分问题;
websocket 是利用 TCP 连接, 建立之后, 可以保持长时间的联系;
减少了多次请求;

var ws = new WebSocket("wss://echo.websocket.org");

ws.onopen = function(evt) {
    console.log("Connection open ...");
    ws.send("Hello WebSockets!");
};

ws.onmessage = function(evt) {
    console.log("Received Message: " + evt.data);
    ws.close();
};

ws.onclose = function(evt) {
    console.log("Connection closed.");
};

XMLHttpRequest 代码类似;
不过 onmessage 中可以多次触发;

因为, 近期学习了Rails, 使用了 Action Cable , 提供的npm包进行的
客户端与服务端的交互; 这里就不展开说了;

推荐大家看一下 阮一峰websocket
有简单明了的介绍;

之后, 随着工作的接触, 希望能对websocket有更多的了解;

参考文章


转载:https://blog.csdn.net/qq_34120430/article/details/105184674
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场