IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> AJAX--URL--http、https、websocket协议、跨域 -> 正文阅读

[网络协议]AJAX--URL--http、https、websocket协议、跨域

AJAX

AJAX – URL – http、https、websocket协议 – 跨域

一. 客户端与服务器

请添加图片描述

  • 上网过程中,负责获取和消费资源的电脑,叫做客户端。
  • 上网过程中,负责存放和对外提供资源的电脑,叫做服务器。

二. url地址

2.1 概念:URL(全称是UniformResourceLocator)中文叫统一资源定位符,用于标识互联网上每个资源的唯一存放位置。浏览器只有通过URL地址,才能正确定位资源的存放位置,从而成功访问到对应的资源。

常见的URL举例:
http://www.baidu.com
http://www.taobao.com
http://www.cnblogs.com/liulongbinblogs/p/11649393.html

2.2 url地址的组成部分

URL地址一般由三部组成:
① 客户端与服务器之间的通信协议
② 存有该资源的服务器名称
③ 资源在服务器上具体的存放位置

请添加图片描述

2.3 网页的打开过程 ***

请添加图片描述

注意:

客户端与服务器之间的通信过程,分为 请求 – 处理 – 响应 三个步骤。
网页中的每一个资源,都是通过 请求 – 处理 – 响应 的方式从服务器获取回来的。

面试题:从输入URL到页面展示,这中间发生了什么

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UiNaRme9-1631186210983)(.\images\dns.png)]

  1. 用户输入关键词,地址栏判断是搜索内容还是url地址。
    如果是搜索内容,会使用浏览器默认搜索引擎加上搜索内容合成url;
    如果是域名会加上协议(如https)合成完整的url。
  2. 然后按下回车。浏览器进程通过IPC(进程间通信)把url传给网络进程(网络进程接收到url才发起真正的网络请求)。
  3. 网络进程接收到url后,先查找有没有缓存。(强制缓存和协商缓存 https://www.cnblogs.com/tugenhua0707/p/10807289.html)
    有缓存,直接返回缓存的资源。
    没有缓存。(进入真正的网络请求)。首先获取域名的IP,系统会首先自动从hosts文件中寻找域名对应的 IP 地址,一旦找到,和服务器建立TCP连接;如果没有找到,则系统会将网址提交 DNS 域名解析服务器进行 IP 地址的解析。
  4. 利用IP地址和服务器建立TCP连接(3次握手4次挥手了解)。
  5. 建立连接后,浏览器构建数据包(包含请求行,请求头,请求正文,并把该域名相关Cookie等数据附加到请求头),然后向服务器发送请求消息。
  6. 服务器接收到消息后根据请求信息构建响应数据(包括响应行,响应头,响应正文),然后发送回网络进程。
  7. 网络进程接收到响应数据后进行解析。
    如果发现响应行的返回的状态码为301,302,说明服务器要我们去找别人要数据,找谁呢?找响应头中的Location字段要,Location的内容是需要重定向的地址url。获取到这个url一切重新来过。
    如果返回的状态码为200,说明服务器返回了数据。
  8. 好了,获取到数据以什么方式打开呢?打开的方式不对的话也不行。打开的方式就是 Content-Type。这个属性告诉浏览器服务器返回的数据是什么类型的。如果返回的是网页类型则为 text/html,如果是下载文件类型则为 application/octet-stream 等等。打开的方式不对,则得到的结果也不对。
    如果是下载类型,则该请求会被提交给浏览器的下载管理器,同时该请求的流程到此结束。
    如果是网页类型,那么浏览器就要准备渲染页面了。
  9. 渲染页面开始。浏览器进程发出“提交文档”(文档是响应体数据)消息给渲染进程,渲染进程接收到消息后会和网络进程建立传输数据的通道,网络进程将“文档”传输给渲染进程。
  10. 一旦开始传输,渲染进程便开始渲染界面

渲染流程: 特别耗性能 。框架 使用 虚拟dom

构建 DOM 树
输入:HTML 文档;
处理:HTML 解析器解析;
输出:DOM 数据解构。
样式计算
输入:CSS 文本;
处理:属性值标准化,每个节点具体样式(继承、层叠);
输出:styleSheets(CSSOM)。
布局(DOM 树中元素的计划位置)
DOM & CSSOM 合并成渲染树;
布局树(DOM 树中的可见元素);
布局计算。
分层
特定节点生成专用图层,生成一棵图层树(层叠上下文、Clip,类似 PhotoShop 里的图层);
拥有层叠上下文属性(明确定位属性、透明属性、CSS 滤镜、z-index 等)的元素会创建单独图层;
没有图层的 DOM 节点属于父节点图层;
需要剪裁的地方也会创建图层。
绘制指令
输入:图层树;
渲染引擎对图层树中每个图层进行绘制;
拆分成绘制指令,生成绘制列表,提交到合成线程;
输出:绘制列表。
分块
合成线程会将较大、较长的图层(一屏显示不完,大部分不在视口内)划分为图块(tile, 256256, 512512)。
光栅化(栅格化)
在光栅化线程池中,将视口附近的图块优先生成位图(栅格化执行该操作);
快速栅格化:GPU 加速,生成位图(GPU 进程)。
合成绘制
绘制图块命令——DrawQuad,提交给浏览器进程;
浏览器进程的 viz 组件,根据DrawQuad命令,绘制在屏幕上。

  1. 传输完毕,渲染进程会发出“确认提交”消息给浏览器进程。

  2. 浏览器在接收到“确认提交”消息后,更新浏览器界面状态(包括地址栏信息,仟前进后退历史,web页面和网站安全状态)。

  3. 页面此时可能还没有渲染完毕,而一旦渲染完毕,渲染进程会发送一个消息给浏览器进程,浏览器接收到这个消息后会停止标签图标的加载动画。

自此,一个完整的页面形成了。

2.4 网页中如何请求数据

如果要在网页中请求服务器上的数据资源,则需要用到 XMLHttpRequest 对象。
XMLHttpRequest(简称 xhr)是浏览器提供的 js 成员,通过它,可以请求服务器上的数据资源。
最简单的用法 var xhrObj = new XMLHttpRequest()

三. ajax

Ajax 的全称是 Asynchronous Javascript And XML(异步 JavaScript 和 XML)。
通俗的理解:Ajax使用XMLHttpRequest对象与服务器端脚本进行通信,支持“异步”通信

  • 节省用户操作时间,提高用户体验,减少数据请求
  • 传输获取数据
  • AJAX = 异步 JavaScriptXML标准通用标记语言的子集)。
  • AJAX 是一种用于创建快速动态网页的技术。
  • 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行局部更新

3.1 ajax优点

  • 减少数据传输
  • 减轻Web 服务器负荷
  • 页面无刷新,提供更好客户体验度的程序

3.2 ajax缺点

  • 存书签问题(解决)
    由于执行动作URL不跳转,所以无法存书签,无法收藏分享链接(可以通过浏览器hash、history来判断和加载不同动作)
  • 浏览器前进后退问题(解决)
    浏览器中的操作无法正常前进后退按钮(HTML5后,可以通过window.history.state实现)
  • SEO问题
    搜索引擎无法抓取和收录Ajax内部请求的内容,不利于seo收录网站 ,vue ssr 服务器端渲染(解决的)
  • 网络延迟问题
    使用一个可视化的组件来告诉用户系统正在进行后台操作并且正在读取数据和内容
  • 流媒体内容支持有限(不存在)
    XMLHttpRequest2提供了更好支持
  • 设备支持问题(不存在)
    一些旧的手持设备(如手机、PDA等)对JS和Ajax支持有限

3.3 ajax流程***

面试题: 背下来 ***

1.打开浏览器,发送请求

2.向地址栏输入地址

3.回车提交

4.等待服务器返回数据,并且接收

5.渲染到页面上

需要使用的知识点:

  • Open方法 打开某个链接 需定义三个参数

  • xhr.open("GET","test1.txt",true);
    
  • 三个参数的含义
    1、提交方式 Form-method
    2、提交地址 Form-action
    3、异步(同步)默认为true 表示是异步请求

  • Send方法
    发送数据请求,相当于Form的submit

  • 请求状态监控
    onreadystatechange事件
    readyState属性:请求状态
    0 (未初始化)还没有调用open()方法
    1 (载入)已调用send()方法,正在发送请求
    2 (载入完成)send()方法完成,已收到全部响应内容
    3 (解析)正在解析响应内容
    4 (完成)响应内容解析完成,可以在客户端调用了
    status属性:服务器(请求资源)的状态
    返回的内容
    responseText:返回以文本形式存放的内容
    responseXML:返回XML形式的内容

完整流程

<button id="btn">点击获取数据</button>
    <div id="con"></div>
    <script>
        window.onload = function () {
            //获取dom节点
            var oBtn = document.getElementById("btn");
            var oCon = document.getElementById("con");
            //绑定事件
            oBtn.onclick = function () {
                // 1.使用 XMLHttpRequest 创建 ajax对象
                //创建 ajax对象
                var xhr = new XMLHttpRequest();
                // 2.向地址栏输入地址  使用 open函数设置请求方式,请求地址,是否异步
                //打开浏览器,设置 请求方式,请求地址,是否异步
                xhr.open("get", "./user.json", true);
                // 3.回车提交 使用 send发送请求
                xhr.send();
                // 4.绑定 onreadystatechange 事件 ,等待服务器返回数据, 并且接收
                //绑定 onreadystatechange 事件  ,当 url请求的状态值发生变化时会触发这个事件
                xhr.onreadystatechange = function () {
                    if (xhr.readyState == 4) {//数据已经从 服务器端返回了
                        //接收数据
                        var data = xhr.responseText;
                        //console.log( data);
                        // 5.需要将 字符串转json对象,渲染到页面上
                        //需要将 字符串转json对象
                        var datajson = JSON.parse(data);
                        console.log(datajson);
                        oCon.innerHTML = `<span>名字:${datajson.name}</span><span>年龄:${datajson.age}</span>`;
                    }
                }
            }
        }
    </script>

抛出异常处理:

 var aa = 12;
//代码不想报错,然后又想知道有没有错误,错误是什么,就可以使用 捕获异常
try {
    alert(a);
} catch (e) {//捕获异常
    console.log(e);
}

ajax ie浏览器兼容性处理,使用抛出异常

try {
    var xhr = new XMLHttpRequest();
} catch (e) {
    var xhr = ActiveXObject("Microsoft.XMLHTTP");//ie低版本
}

3.4 ajax提交数据到php服务器端

3.4.1 准备工作

a.安装 phpstudy

b.打开面板后,左侧选择网站,打开面板后左上角有个创建网站按钮,点击后创建新站点,

c.将准备好的php文件拷贝进去

d.启动 Apache服务器

3.4.2 get方式提交

<button id="btn">点击获取数据</button>
<div id="con"></div>
<script>
   window.onload = function () {
       var oBtn = document.getElementById("btn");
       var oCon = document.getElementById("con");
       oBtn.onclick = function () {
           var xhr = new XMLHttpRequest();
           //get传参
           xhr.open("get", "./get.php?user=lili&pwd=123456", true);
           xhr.send();
           xhr.onreadystatechange = function () {
               if (xhr.readyState == 4) {//数据已经从 服务器端返回了
                   var data = xhr.responseText;
                   console.log(data);

                   oCon.innerHTML = `<span>${data}</span>`;
               }
           }
       }
   }
   //注意:本实例,需要使用 php 的服务器才能解析 get.php的文件
   //打开小皮,启动 Apache
   //在浏览器输入:http://127.0.0.1/04-ajax-get.html

get方式的数据提交服务器一般跟在url的后面,get方式提交的数据有大小限制

-  **Firefox** 3.0.3: 当$len 赋值为4053时出错,可见最长字长4098
-  IE7.0: 2083, 结果与官方说法一致
-  Opera 9.60: 4098 , **Firefox**3.0.3 相同
-   google chrome 0.2.149.30: 4098, 与**Firefox**3.0.3,Opera 9.60相同
xhr.open('get','get.php?user=qqq&pwd=123456',true);

3.4.3 post方式提交

优点:1.使用 头部将post数据提交到 服务端,不会显示在 地址栏,更安全;2.post方式传输的数据量不限制

? post 数据加密了么? 没加密

? 加密:1.使用 MD5、sha1 、对称加密、非对称加密 (手动写)

? 2.https协议

xhr.open('post','post.php',true);
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
//3.回车提交
xhr.send('user=lili&pwd=123456');

3.5 ajax封装 了解内容

各位同学,发现了没有,ajax的好多代码都是固定格式的,所以,我们需要把他封装一下,以方便我们后期调用。

//参数:

method 请求方式

url 请求地址

success 回调函数

data 带给 服务端的数据

type 同步还是异步

ajax.js

//参数:
// method  请求方式  string
// url     请求地址  string
// success 回调函数  function
// data    带给 服务端的数据  string
// type    同步还是异步    boolean
function ajax(method, url, data, success, type) {
    //1.创建 xml 对象
    try {
        var xhr = new XMLHttpRequest();
    } catch (e) {
        var xhr = ActiveXObject("Microsoft.XMLHTTP");
    }
    xhr.open(method, url, type);
    //判断请求方式
    if (method == "get") {
        xhr.send();
    } else {
        xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
        xhr.send(data);
    }

    //绑定事件
    xhr.onreadystatechange = function () {
        //判断 数据是不是正常传回来了
        if (xhr.readyState == 4) {
            //保险  status == 200 服务器端正常返回
            if (xhr.status == 200) {
                success && success(xhr.responseText);
            } else {
                alert("访问出错");
            }

        }
    }
}

调用:

<button id="btn">点击获取数据</button>
    <div id="con"></div>
    <script src="./ajax.js"></script>
    <script>
        window.onload = function () {
            var oBtn = document.getElementById("btn");
            var oCon = document.getElementById("con");
            oBtn.onclick = function () {
                //function ajax(method, url, data, success, type) 
                ajax("get", "./getNews.php", "", function (data) {
                    console.log(data);
                    var datajson = JSON.parse(data);
                    str = "";
                    datajson.forEach((item, index) => {
                        str += `<p >${item.title} - ${item.date}</p>`;
                    })
                    oCon.innerHTML = str;
                }, true);
            }
        }
    </script>

四.表单提交数据

4.1 什么是表单

表单 即form,可以向服务器提交数据,比如:提交用户信息

  • action 提交到哪里
  • method 提交方式

4.2 Get和Post的区别

  • 传输方式的区别
    Get通过url地址传输
    Post通过浏览器内部传输
  • 传输数据量
    Get有数据量限制,每个浏览器都不同
    Post理论上无限

实例:

get:

<form action="get.php" method="get">
        <!-- 表单提交时,表单项一定要写name 
        get方式 数据是在url后面传输到服务端的,大小有限制,不安全
        -->
        <input type="text" name="user" id="" />
        <input type="password" name="pwd" id="" />
        <button type="submit">提交表单</button>
    </form>

post:

<form action="post.php" method="post">
        <!-- 表单提交时,表单项一定要写name 
        post方式 数据是在传输包的头部传输到服务端的 ,大小无限制,和get相比更安全
        -->
        <input type="text" name="user" id="" />
        <input type="password" name="pwd" id="" />
        <button type="submit">提交表单</button>
    </form>

五.jquery ajax

浏览器中提供的 XMLHttpRequest 用法比较复杂,所以 jQuery 对 XMLHttpRequest 进行了封装,提供了一系列 Ajax 相关的函数,极大地降低了 Ajax 的使用难度。
jQuery 中发起 Ajax 请求最常用的三个方法如下:

  • $.get()
  • $.post()
  • $.getJSON()
  • $.ajax()

5.1 $.get()函数的语法

jQuery 中 $.get() 函数的功能单一,专门用来发起 get 请求,从而将服务器上的资源请求到客户端来进行使用。
$.get() 函数的语法如下:

$.get(url,[data],[callback])

参数:

  • url 要请求的资源地址
  • data 请求资源期间要携带的参数
  • callback 请求成功是的回调函数
//get方式获取
$.get('film.json',function(data){
    console.log(data);
})

5.2 $.post()函数的语法

 $(function () {
            $.ajax({
                type: "post",
                url: "http://www.51houniao.com/requirement/request/getMatchedProducts",
                data: JSON.stringify({
                    desc: false,
                    orderBy: "outtime",
                    product_type: 2,
                    pageSize: 100
                }),//候鸟的后台不支持 对象形式的参数
                contentType: "application/json;charset=UTF-8",//设置头部
                success: function (data) {
                    console.log(data);
                }
            })


        })

5.3 $.getJSON()函数写法

//getJSON  专门获取json数据的
$.getJSON('film.json',function(data){
    console.log(data);
});

5.4 $.ajax() 函数

相比于 $.get() 和 $.post() 函数,jQuery 中提供的 $.ajax() 函数

$.ajax({
    type:"get",//获取数据的方式  get  post   
    url:"film.json",//url地址  如果访问的是php,那么请打开php的服务器   必选
    async:true,//异步
    data:"",//获取数据时的传参
    dataType:"json",//返回值类型   jsonp 支持跨域 
    success:function(data){//成功的回调函数  必选
        console.log(data);
        //jquery返回的数据不需要解析
        var data = data.data.films;
        for(var i = 0;i<data.length;i++){
            var $li = $('<li>'+data[i].name+'</li>');
            $('#con').append($li);
        }
    },
    error:function(e){
        console.log(e);
    }
})

六.跨域***

6.0 为什么会出现跨域问题

因为 ,浏览器同源策略,增加安全性,同源策略又叫同域(域名)策略
只有同一个域名下的数据可以相互访问,不同域名下进行相互之间访问时就会被组织,提示你蛞蝓了,子域名不一样与会存在跨域问题

1.在同一个公司 ,163 ,做不同业务的需要的子域名不一样,解决跨域问题

2.爬取其他网站的数据, 需要解决跨域问题

注意:微信 用户不需要考虑跨域问题,ios、安卓没有跨域问题

	出于浏览器的同源策略限制。**同源策略**(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

请添加图片描述

跨域限制

【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB

【2】无法接触非同源网页的 DOM

【3】无法向非同源地址发送 AJAX 请求 ***

跨域实例:

演示跨域
<script src="./js/jquery.min.js"></script>
<script>
  $(function () {
      $.get("http://127.0.0.1/getNews.php", "", function (data) {
          console.log(data);
      });
  })
  //实例,需要在 vscode中点击右键菜单打开
  //打开的地址:http://127.0.0.1:5501/01-ajax-kuayu.html
  //http://127.0.0.1:5501 请求 http://127.0.0.1/getNews.php ,所以产生了跨域
  /*
      报错:
      Access to XMLHttpRequest at 'http://127.0.0.1/getNews.php' from origin 'http://127.0.0.1:5501' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
      */
</script>

2.运行程序,会看到跨域
3.在浏览器-开发者工具中会看到

已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8888/getNews.php 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。

说明跨域了

解决跨域的常用方式有以下几种:

6.1 后台设置允许跨域请求 CORS header(‘Access-Control-Allow-Origin: *’);

这种前端工程师了解即可

6.2原生js解决跨域 **

1.原生解决跨域问题的原理

js跨域的原理
    <script>
        function success(data) {
            console.log("拿到数据了");
            console.log(data);
        }
    </script>
    <script>
        success({ name: "lili", age: 18 })
    </script>

getdata.js

success({ name: "lili", age: 18 })

html

<!-- script 标签的 src属性 天生具备跨域能力 -->
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        function success(data) {
            console.log("拿到数据了");
            console.log(data);
        }
    </script>
    <script src="./js/getdata.js?callback=success"></script>
    <!-- callback=success 就相当于  success({ name: "lili", age: 18 }) -->

原生js解决跨域问题

/*
        1. script标签的src属性 天生就具备 跨域能力
        2.js原生跨域必须后台代码支持
        */
        window.onload = function () {
            //创建 script标签
            var oScript = document.createElement("script");
            oScript.src = "http://127.0.0.1/getNewsjs.php?callback=success";
            var oHeader = document.getElementsByTagName('head')[0];
            oHeader.appendChild(oScript);
        }
        function success(data) {
            console.log(data);
        }

百度搜索的实例

<input type="text" name="word" id="word" placeholder="请输入想要搜索的内容" />
    <button id="btn">搜索</button>
    <div id="con"></div>
    <script>
        var oCon = document.getElementById("con");
        //https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=js&cb=JSON_yy
        //需求:输入关键字,点击 按钮搜索内容
        window.onload = function () {
            //1.获取dom
            var oBtn = document.getElementById("btn");
            var oWord = document.getElementById("word");

            //2.绑定事件
            oBtn.onclick = function () {
                //3.获取文本框内容
                var txt = oWord.value;
                //4.跨域获取 百度搜索的数据
                //4.1 创建 标签
                var oScript = document.createElement("script");
                oScript.src = "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=" + txt + "&cb=success";
                //cb 因为 咱百度的后台工程师定义的接收变量的可以是 cb
                var oHead = document.getElementsByTagName("head")[0];
                oHead.appendChild(oScript);

            }
        }
        function success(data) {
            console.log(data);
            var str = "";
            data.s.forEach(item => {
                str += `<p>${item}</p>`;
            })
            oCon.innerHTML = str;
        }
    </script>

6.3 jquery jsonp解决跨域

	<script src="./js/jquery.min.js"></script>
    <script>
        $(function () {
            $.ajax({
                type: "get",
                url: "http://127.0.0.1/getNewsjs.php",
                data: "",
                async: true,
                dataType: "jsonp",//表示支持跨域 ,
                success: function (data) {
                    console.log(data);
                },
                error: function (err) {
                    console.log(err);
                }
            })
        })
        //jquery 跨域的原理:和js的跨域的原理一样,只不过,咱jquery工程师,将 js的跨域封装到了  dataType: "jsonp"
    </script>

6.4 在前端还可以在打包前使用proxy配置解决跨域,很常用 ***

6.5 后台配置 nginx 反向代理服务器 解决跨域 ***

6.6 ajax 配合 promise使用 ***

手写promise

      var pro = new Promise(function(resolve, reject){
            setTimeout(function(){
                //resolve('success');
                reject('fail');
            }, 2000);
        });
        pro.then(function(res){
            //接收成功的数据
            console.log(res);
        }, function(err){
            //接收失败的数据
            console.log(err);
        })

ajax在使用的时候,如果是多个数据请求,容易产生地狱回调问题,可以使用 promise解决

例如:

$(function () {
            $.getJSON('./json/01.json', function (data) {
                console.log(data);
                var list = data.matchedProducts;
                for (var i = 0; i < list.length; i++) {
                    var $li = $(`<li>${list[i].collection_num} - ${list[i].pro_title}</li>`);
                    $('#list').append($li);
                }
                //调用 第二页数据
                $.getJSON('./json/02.json', function (data) {
                    console.log(data);
                    var list = data.matchedProducts;
                    for (var i = 0; i < list.length; i++) {
                        var $li = $(`<li>${list[i].collection_num} - ${list[i].pro_title}</li>`);
                        $('#list').append($li);
                    }
                    //调用 第三页数据
                    $.getJSON('./json/03.json', function (data) {
                        console.log(data);
                        var list = data.matchedProducts;
                        for (var i = 0; i < list.length; i++) {
                            var $li = $(`<li>${list[i].collection_num} - ${list[i].pro_title}</li>`);
                            $('#list').append($li);
                        }
                    })
                })
            })


        })

以上实例,可以使用promise解决

$(function () {
            function getJson(page) {
                //创建peomise对象
                var p = new Promise(function (resolve, reject) {
                    //获取数据
                    $.getJSON("./json/0" + page + ".json", function (data) {
                        //将获取到的后台数据使用 resolve带回
                        resolve(data);
                    })
                });
                return p;
            }
            //渲染页面的函数
            function writeHTML(data) {
                var list = data.matchedProducts;
                for (var i = 0; i < list.length; i++) {
                    var $li = $(`<li>${list[i].collection_num} - ${list[i].pro_title}</li>`);
                    $('#list').append($li);
                }
            }

            //调用 promise
            getJson(1).then(function (data) {
                console.log(data);
                // 渲染页面
                writeHTML(data);
                //获取第二页数据
                return getJson(2)
            }).then(function (data) {
                // 渲染页面
                writeHTML(data);
                //获取第二页数据
                return getJson(3)
            }).then(function (data) {
                // 渲染页面
                writeHTML(data);
            }).catch(function (err) {
                console.log(err);
            })
        })

promise.all的使用

$(function () {
            const p1 = new Promise(function (resolve, reject) {
                $.getJSON("./json/01.json", function (data) {
                    resolve(data);
                })
            })
            const p2 = new Promise(function (resolve, reject) {
                $.getJSON("./json/02.json", function (data) {
                    resolve(data);
                })
            })
            const p3 = new Promise(function (resolve, reject) {
                $.getJSON("./json/03.json", function (data) {
                    resolve(data);
                })
            })


            //渲染页面的函数
            function writeHTML(list) {
                for (var i = 0; i < list.length; i++) {
                    var $li = $(`<li>${list[i].collection_num} - ${list[i].pro_title}</li>`);
                    $('#list').append($li);
                }
            }

            //调用 Promise.all
            //如果数据组中的promise有一个返回是错误的,那么promise不会继续进行
            Promise.all([p1, p2, p3]).then((res) => {
                //console.log(res);
                //重组数据
                var mydata = [];
                res.forEach((item, index) => {
                    mydata = mydata.concat(item.matchedProducts);
                })
                console.log(mydata);
                writeHTML(mydata)
            })
        })
Promise.race的使用

顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

Promise.allSettled 的使用

在多个promise同时进行时咱们很快会想到使用Promise.all来进行包装, 但是由于Promise.all的短路特性, 三个提交中若前面任意一个提交失败, 则后面的表单也不会进行提交了, 这就与咱们需求不符合.

Promise.allSettledPromise.all类似, 其参数接受一个Promise的数组, 返回一个新的Promise, 唯一的不同在于, 其不会进行短路, 也就是说当Promise全部处理完成后我们可以拿到每个Promise的状态, 而不管其是否处理成功.

6.7 axios 的使用

6.7.1 restful API的使用

在后续的前后端分离式开发中,常见的增删改查不再是纯粹的GET+POST的两种请求方式,而是分的更加细化:

  • GET:查询请求类型
    • 取全部的数据(列表)
    • 取单个的数据(详情)
  • POST:新增请求类型
    • 新增是不带条件
  • PUT:修改请求类型
    • 修改是要条件的
    • 修改条件的传递是通过地址栏传递的(restful规范)
    • 修改的数据主体是通过请求体传递的(请求体发送方式与post一致)
  • DELETE:删除请求类型
    • 删除需要条件的
    • 条件通过地址栏传递的

这种对请求方法(请求动词)约束的规范叫做restFul规范(整理什么是restful)。该规范不是硬性要求,但是接口设计的时候一般都会遵守,其规范的不仅仅是请求方式,在请求地址形式、响应状态码等方面也存在规范要求(具体的要求项目时再说)。

6.7.2 axios

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。axios对ajax进行了封装,返回promise对象,比ajax更简洁好用

特性

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应 ***
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

6.7.1 axios.get

axios.get("http://www.51houniao.com/product/product/guessYouLike").then(res => {
            console.log(res);
            //渲染页面
            var str = "";
            res.data.forEach((item, index) => {
                str += `<li>${item.proTitle}</li>`;
            })
            document.querySelector('#like').innerHTML = str;
        })

6.7.2 axios.post

//参数: 参数一:url地址;参数二: 传给服务器的json对象数据
        axios.post("http://www.51houniao.com/requirement/request/getMatchedProducts", {
            desc: false,
            orderBy: "outtime",
            pageSize: 100,
            product_type: 2,
        }).then(res => {
            console.log(res);
            //渲染页面
            var str = "";
            res.data.matchedProducts.forEach((item, index) => {
                str += `<li>${item.pro_title}</li>`;
            })
            document.querySelector('#like').innerHTML = str;
        })

6.7.3 //支持多个并发请求

        function getData1() {
            return axios.get("./json/01.json");
        }
        function getData2() {
            return axios.get("./json/02.json");
        }

        //axios的并发请求
        axios.all([getData1(), getData2()]).then(res => {
            console.log(res);
            var mydata = [];
            res.forEach((item, index) => {
                mydata = mydata.concat(item.data.matchedProducts);
            })
            console.log(mydata);
            //渲染

        })

6.7.4 axios 通用写法

       axios({
            method: 'get',
            url: './json/01.json',
            data: {}
        }).then(res => {
            console.log(res);
        })

6.7.5 请求方法的别名

为方便起见,为所有支持的请求方法提供了别名

axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
注意

在使用别名方法时, urlmethoddata 这些属性都不必在配置中指定。

6.7.6 拦截器

在请求或响应被 thencatch 处理前拦截它们。

        var aa = 123;
        try{
            alert(a);
        }catch(e){  //exception
            alert(e);  // 捕获异常
        }
        alert(666);


//then
axios.get(url).then(res=>{
    ...
})

参考:http://www.axios-js.com/zh-cn/docs/#axios-API

6.8 async await

async await 的语法糖 es7之后才出现 和 promise 、generator都有一定的关系,

async-awaitpromisegenerator的语法糖。只是为了让我们书写代码时更加流畅,当然也增强了代码的可读性。

async 表示异步,属于异步操作的关键字


三页数据顺序执行使用 async await


七.http协议 https协议 websocket协议

7.1 超文本传输协议

客户端与服务器之间要实现网页内容的传输,则通信的双方必须遵守网页内容的传输协议。

网页内容又叫做超文本,因此网页内容的传输协议又叫做超文本传输协议(HyperText Transfer Protocol) ,简称 HTTP 协议。

请添加图片描述

7.2 HTTP请求消息的组成部分

由于 HTTP 协议属于客户端浏览器和服务器之间的通信协议。因此,客户端发起的请求叫做 HTTP 请求,客户端发送到服务器的消息,叫做 HTTP 请求消息。

注意:HTTP 请求消息又叫做 HTTP 请求报文。

HTTP 请求消息由请求行(request line)、请求头部( header ) 、空行 和 请求体 4 个部分组成。

请添加图片描述

  • a.请求行由请求方式、URL 和 HTTP 协议版本 3 个部分组成,他们之间使用空格隔开。

请添加图片描述

请添加图片描述

  • b. 请求头部

请求头部用来描述客户端的基本信息,从而把客户端相关的信息告知服务器。比如:
User-Agent 用来说明当前是什么类型的浏览器;
Content-Type 用来描述发送到服务器的数据格式;
Accept 用来描述客户端能够接收什么类型的返回内容;
Accept-Language 用来描述客户端期望接收哪种人类语言的文本内容。
请求头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔。
在这里插入图片描述

关于更多请求头字段的描述,可以查看 MDN 官方文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

  • c. 请求体

请求体中存放的,是要通过 POST 方式提交到服务器的数据。

注意:只有 POST 请求才有请求体,GET 请求没有请求体!

7.3 HTTP响应消息

响应消息就是服务器响应给客户端的消息内容,也叫作响应报文。

HTTP响应消息由状态行、响应头部、空行 和 响应体 4 个部分组成,如下图所示:
在这里插入图片描述

  • a. 状态行

状态行由 HTTP 协议版本、状态码和状态码的描述文本 3 个部分组成,他们之间使用空格隔开;
在这里插入图片描述
在这里插入图片描述

  • b. 响应头部

响应头部用来描述服务器的基本信息。响应头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔。
在这里插入图片描述
在这里插入图片描述

关于更多响应头字段的描述,可以查看 MDN 官方文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

  • c. 响应体

响应体中存放的,是服务器响应给客户端的资源内容。
在这里插入图片描述
在这里插入图片描述

7.4 HTTP请求方法

HTTP 请求方法,属于 HTTP 协议中的一部分,请求方法的作用是:用来表明要对服务器上的资源执行的操作。最常用的请求方法是 GET 和 POST。

请添加图片描述

7.5 HTTP响应状态码

HTTP 响应状态码(HTTP Status Code),也属于 HTTP 协议的一部分,用来标识响应的状态。
响应状态码会随着响应消息一起被发送至客户端浏览器,浏览器根据服务器返回的响应状态码,就能知道这次 HTTP 请求的结果是成功还是失败了。

HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字用来对状态码进行细分。
HTTP 状态码共分为 5 种类型:

请添加图片描述

完整的 HTTP 响应状态码,可以参考 MDN 官方文档 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status

常用的状态码:

2**

在这里插入图片描述

3**
在这里插入图片描述

4** 客户端错误,很大几率西药前端工程师 出手

在这里插入图片描述405 请求方式不对
415 请求时传送给服务器的参数不对

5**

在这里插入图片描述

7.6 https协议

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 [1] 。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面

HTTP的缺点

HTTP虽然使用极为广泛, 但是却存在不小的安全缺陷, 主要是其数据的明文传送和消息完整性检测的缺乏, 而这两点恰好是网络支付, 网络交易等新兴应用中安全方面最需要关注的 [3] 。

关于 HTTP的明文数据传输, 攻击者最常用的攻击手法就是网络嗅探, 试图从传输过程当中分析出敏感的数据, 例如管理员对 Web 程序后台的登录过程等等, 从而获取网站管理权限, 进而渗透到整个服务器的权限。即使无法获取到后台登录信息, 攻击者也可以从网络中获取普通用户的隐秘信息, 包括手机号码, 身份证号码, 信用卡号等重要资料, 导致严重的安全事故。进行网络嗅探攻击非常简单, 对攻击者的要求很低。使用网络发布的任意一款抓包工具, 一个新手就有可能获取到大型网站的用户信息 [3] 。

另外,HTTP在传输客户端请求和服务端响应时, 唯一的数据完整性检验就是在报文头部包含了本次传输数据的长度, 而对内容是否被篡改不作确认。 因此攻击者可以轻易的发动中间人攻击, 修改客户端和服务端传输的数据, 甚至在传输数据中插入恶意代码, 导致客户端被引导至恶意网站被植入木马 [3] 。

改进目标

HTTPS 协议是由 HTTP 加上 TLS/SSL 协议构建的可进行加密传输、身份认证的网络协议,主要通过数字证书加密算法、非对称密钥等技术完成互联网数据传输加密,实现互联网传输安全保护。设计目标主要有三个。

(1)数据保密性:保证数据内容在传输的过程中不会被第三方查看。就像快递员传递包裹一样,都进行了封装,别人无法获知里面装了什么 [4] 。

(2)数据完整性:及时发现被第三方篡改的传输内容。就像快递员虽然不知道包裹里装了什么东西,但他有可能中途掉包,数据完整性就是指如果被掉包,我们能轻松发现并拒收 [4] 。

(3)身份校验安全性:保证数据到达用户期望的目的地。就像我们邮寄包裹时,虽然是一个封装好的未掉包的包裹,但必须确定这个包裹不会送错地方,通过身份校验来确保送对了地方 [4] 。

HTTPS协议的改进

双向的身份认证

客户端服务端在传输数据之前,会通过基于X.509证书对双方进行身份认证 。具体过程如下 [3] :

客户端发起 SSL 握手消息给服务端要求连接。

服务端将证书发送给客户端。

客户端检查服务端证书,确认是否由自己信任的证书签发机构签发。 如果不是,将是否继续通讯的决定权交给用户选择 ( 注意,这里将是一个安全缺陷 )。如果检查无误或者用户选择继续,则客户端认可服务端的身份。

服务端要求客户端发送证书,并检查是否通过验证。失败则关闭连接,认证成功则从客户端证书中获得客户端的公钥,一般为1024位或者 2048位。到此,服务器客户端双方的身份认证结束,双方确保身份都是真实可靠的。

数据传输的机密性

客户端和服务端在开始传输数据之前,会协商传输过程需要使用的加密算法。 客户端发送协商请求给服务端, 其中包含自己支持的非对称加密的密钥交换算法 ( 一般是RSA), 数据签名摘要算法 ( 一般是SHA或者MD5) , 加密传输数据的对称加密算法 ( 一般是DES),以及加密密钥的长度。 服务端接收到消息之后,选中安全性最高的算法,并将选中的算法发送给客户端,完成协商。客户端生成随机的字符串,通过协商好的非对称加密算法,使用服务端的公钥对该字符串进行加密,发送给服务端。 服务端接收到之后,使用自己的私钥解密得到该字符串。在随后的数据传输当中,使用这个字符串作为密钥进行对称加密 [3] 。

防止重放攻击

SSL使用序列号来保护通讯方免受报文重放攻击。这个序列号被加密后作为数据包的负载。在整个SSL握手中,都有一个唯一的随机数来标记SSL握手。 这样防止了攻击者嗅探整个登录过程,获取到加密的登录数据之后,不对数据进行解密, 而直接重传登录数据包的攻击手法。

可以看到,鉴于电子商务等安全上的需求,HTTPS对比HTTP,在安全方面已经取得了极大的增强。总结来说,HTTPS的改进点在于创造性的使用了非对称加密算法,在不安全的网路上,安全的传输了用来进行对称加密的密钥,综合利用了非对称加密的安全性和对称加密的快速性 [3] 。

HTTPS与HTTP原理区别

HTTPS 主要由两部分组成:HTTP + SSL / TLS,也就是在 HTTP 上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过 TLS 进行加密,所以传输的数据都是加密后的数据。

HTTP 原理

① 客户端的浏览器首先要通过网络与服务器建立连接,该连接是通过TCP 来完成的,一般 TCP 连接的端口号是80。 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是 MIME 信息包括请求修饰符、客户机信息和许可内容 [2] 。

② 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是 MIME 信息包括服务器信息、实体信息和可能的内容 [2] 。

HTTPS 原理

① 客户端将它所支持的算法列表和一个用作产生密钥的随机数发送给服务器

② 服务器从算法列表中选择一种加密算法,并将它和一份包含服务器公用密钥的证书发送给客户端;该证书还包含了用于认证目的的服务器标识,服务器同时还提供了一个用作产生密钥的随机数

③ 客户端对服务器的证书进行验证(有关验证证书,可以参考数字签名),并抽取服务器的公用密钥;然后,再产生一个称作 pre_master_secret 的随机密码串,并使用服务器的公用密钥对其进行加密(参考非对称加 / 解密),并将加密后的信息发送给服务器

④ 客户端与服务器端根据 pre_master_secret 以及客户端与服务器的随机数值独立计算出加密和 MAC密钥(参考 DH密钥交换算法

⑤ 客户端将所有握手消息的 MAC 值发送给服务器

⑥ 服务器将所有握手消息的 MAC 值发送给客户端

优缺点

优点
  1. 使用 HTTPS 协议可认证用户和服务器,确保数据发送到正确的客户机和服务器
  2. HTTPS 协议是由 SSL+HTTP构建的可进行加密传输、身份认证的网络协议,要比 HTTP安全,可防止数据在传输过程中被窃取、改变,确保数据的完整性
  3. HTTPS 是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本
缺点
  1. 相同网络环境下,HTTPS 协议会使页面的加载时间延长近 50%,增加 10%到 20%的耗电。此外,HTTPS 协议还会影响缓存,增加数据开销和功耗
  2. HTTPS 协议的安全是有范围的,在黑客攻击、拒绝服务攻击和服务器劫持等方面几乎起不到什么作用
  3. 最关键的是,SSL 证书的信用链体系并不安全。特别是在某些国家可以控制 CA 根证书的情况下,中间人攻击一样可行
  4. 成本增加。部署 HTTPS 后,因为 HTTPS 协议的工作要增加额外的计算资源消耗,例如 SSL 协议加密算法和 SSL 交互次数将占用一定的计算资源和服务器成本。在大规模用户访问应用的场景下,服务器需要频繁地做加密和解密操作,几乎每一个字节都需要做加解密,这就产生了服务器成本。随着云计算技术的发展,数据中心部署的服务器使用成本在规模增加后逐步下降,相对于用户访问的安全提升,其投入成本已经下降到可接受程度

7.7 http1.0 和 2.0的区别

7.7.1 1.0和1.1 的区别

HTTP1.0最早在网页中使用是在1996年,那个时候只是使用一些较为简单的网页上和网络请求上,而HTTP1.1则在1999年才开始广泛应用于现在的各大浏览器网络请求中,同时HTTP1.1也是当前使用最为广泛的HTTP协议。 主要区别主要体现在:

  1. 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
  2. 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  3. 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
  4. Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
  5. 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

7.7.2 HTTP2.0和HTTP1.X相比的新特性

  • 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
  • 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
  • header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
  • 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。 websocket

参看: https://www.cnblogs.com/heluan/p/8620312.html

7.8 websocket 流程

WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

其他特点包括:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

简单实例:


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.");
};      
  • socket.io:功能强大,支持集成websocket服务器端和Express3框架与一身。

参看:

http://www.ruanyifeng.com/blog/2017/05/websocket.html

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-14 13:44:27  更:2021-09-14 13:46:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 0:42:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码