前端开发必会的网络硬知识

网络基础是一劳永逸的东西。

(必读:https://juejin.im/post/5e527c58e51d4526c654bf41

什么是TCP/IP协议?什么是HTTP协议?

TCP/IP协议分为四层:应用层(DNS 域名系统,HTTP协议,FTP 文件传输协议)、传输层(TCP 传输控制协议,UDP用户数据报协议)、网络层(IP协议 一条传输路线)、链路层(处理连接网络的硬件部分)

发送端=》每通过一层,就增加首部

应用层: http数据

传输层:tcp首部+http数据

网络层:ip首部+tcp首部+ http数据

链路层:以太网首部+ip首部+tcp首部+ http数据

 

接收端=》每通过一层,就删除首部

链路层:以太网首部+ip首部+tcp首部+ http数据

网络层:ip首部+tcp首部+ http数据

传输层:tcp首部+http数据

应用层: http数据

IP协议的作用:将各个数据包准确无误地传递给对方

IP协议负责找到接收方的详细地址,TCP协议负责安全地把东西带给接收方。

 

TCP是传输层,通过字节流服务。将一大块数据分割成以报文段为单位的数据包,将数据安全准确可靠传送给对方。TCP为了更容易传送大数据才进行数据分割,TCP协议可以确认数据最终是否传送给对方。

为了保证信息准确无误可靠地送达,TCP采取了最著名的三次握手策略。

模拟:

A: 在吗? SYN

B:在的。啥事? SYN+ACK

A:去吃饭啦。ACK

转自:https://www.cnblogs.com/laojiao/p/9653108.html

 

HTTP协议特点:客户端每次发送请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程叫做一次连接。

HTTP协议常见的状态码有哪些?

1--信息性状态码

2:200 ok  204 (请求成功,无资源返回) 206(对资源某一部分请求)--成功状态码

3: 301 308(永久重定向) 302,303,307(临时性重定向) 304(资源找到 不符合要求) 303(资源url已更新,是否能临时按照新的url访问)--重定向状态码

1)301 308是永久重定向,302,303,307是临时重定向,304是资源找到,不符合要求

2)301,302是http1.0的内容,303,307,308是http1.1的内容

3)301,302本来在规范中是不允许重定向时改变请求method的(将post改为get),实际上许多浏览器实现的时候,允许重定向改变请求method

4)303的出现是允许重定向时改变请求method。此外303响应禁止被缓存。307,308则不允许重定向时改变method。

4:400(报文错误)401(没有认证信息) 403(forbidden)404(not found) 405( 方法不被允许) 408(请求超时)--客户端错误状态码

5:500(服务器内部错误)502(网关错误)504(超时)503(超负荷)--服务器错误状态码

 

HTTP协议和HTTPS的区别?HTTP2了解吗?

  1. https需要使用ca证书,费用不便宜
  2. http是明文传输,https是通过ssl加密传输
  3. http连接简单,无状态(对事务处理没有记忆能力,服务器不知道客户端是什么状态)
  4. http的端口是80,https的端口是443
  5. https是通过ssl+http构建的用来进行身份认证、加密通信的网络协议,比使用http安全

 

HTTP2(关键并不在于高带宽,而是低延迟

  1. 多路复用
  2. 首部压缩
  3. 支持服务器推送
  4. 二进制分帧

什么是三次握手?什么是四次挥手?

tcp连接

第一次ヽ(○´∀)乂(*´∀`*): client发送SYN=1给server(在?)

第二次ヽ(○´∀)乂(*´∀`*): server使用ACK应答,使用SYN同步,发送SYN+ACK给client(收到了,啥事?)

第三次ヽ(○´∀)乂(*´∀`*):client发送ACK应答(我中彩票了。)

 

tcp断开连接

第一次(ㄏ ̄▽ ̄)ㄏbyeㄟ( ̄▽ ̄ㄟ):client发起中断连接请求,发送Fin报文给server(我发Fin,想要断开连接)

第二次(ㄏ ̄▽ ̄)ㄏbyeㄟ( ̄▽ ̄ㄟ):server发送ACK应答(你发的Fin我收到了)

第三次(ㄏ ̄▽ ̄)ㄏbyeㄟ( ̄▽ ̄ㄟ):server发送Fin报文(我也发Fin,跟你断开连接)

第四次(ㄏ ̄▽ ̄)ㄏbyeㄟ( ̄▽ ̄ㄟ):client发送ACK应答(你发的Fin我也收到了)

 

Server只有等所有应答都发送完,才能发Fin报文。不能同时发送。

 

HTTP和websocket的区别?

答案一:

HTTP1.1通过使用Connection:keep-alive进行长连接,HTTP 1.1默认进行持久连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。这种长连接是一种“伪链接”

websocket的长连接,是一个真的全双工。长连接第一次tcp链路建立之后,后续数据可以双方都进行发送,不需要发送请求头。

keep-alive双方并没有建立正真的连接会话,服务端可以在任何一次请求完成后关闭。WebSocket 它本身就规定了是正真的、双工的长连接,两边都必须要维持住连接的状态。

答案二:

(DNS FTP HTTP)应用-》(TCP)传输-》(IP)网络-》(硬件)链路

http协议是用在应用层的协议,它是基于tcp协议的,http协议建立链接必须要有三次握手才能发送信息。

http连接分为短连接、长连接。短连接是每次请求都要三次握手才能发送自己的信息,即每一个request对应一个response。长连接是在一定得期限内保持连接,保持tcp连接不断开。客户端与服务器通信,必须要有客户端发起然后服务器返回结果。客户端是主动的,服务器是被动的。

 

websocket是为了解决客户端发起多个http请求到服务器资源,浏览器必须经过长时间的轮询问题而生的。他实现了多路复用,它是全双工通信。在websocket协议下客户端和服务器可以同时发送信息。

建立websocket之后,服务器不必在浏览器发送request请求之后才能发送信息到浏览器。这是的服务器已有主动权想什么时候发就可以发送信息到服务器。而且信息当中不必在带有head的部分信息了。

 

与http的长连接通信来说,这种方式不久降低了服务器的压力,而且信息当中也减少了部分多余的信息。

 

什么是DNS?

DNS是建立在分布式数据库上的分层命名系统。

作用:将域名转换成ip地址,并可以将域名分配给internet组资源和用户,无论实体的物理位置如何。

 

请描述用户在浏览器里输入URL后回车,到页面完全展示期间,都发生了什么?

(DNS 解析过程,HTML词法分析和语法分析,CSS解析, 合成图层、合成线程调用光栅化线程池,生成位图后浏览器进程间通信过程,显卡缓存与显示器的关系)

  1. DNS解析:将域名解析成IP地址
  2. TCP连接:TCP三次握手
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 浏览器解析渲染页面
  6. 断开连接:TCP四次挥手

 

  • URL:统一资源定位符,网址。
    scheme://host.domain:port/path/filename
    scheme-因特网服务的类型。常见协议有:http,https,ftp,file。最常见的是http,而https是进行加密的网络传输。
    host-域主机(http的默认主机是www)
    domain-因特网域名,比如w3school.com.cn
    port-主机上的端口号(http默认是80端口,https默认是443端口)
    path-服务器上的路径
    filename-文档/资源的名称

---缓存

 

  • 域名解析(DNS)
    用于将主机名和域名转换成IP地址
    解析过程:1、先从本地host文件中查找是否有对应域名的IP关系,如果有即向IP地址发起请求,如果没有,将到DNS服务器中查找。
    2、DNS分为本地DNS服务器,根DNS服务器和各个子DNS服务器。
    根DNS下面有com DNS服务器、org DNS服务器、edu DNS服务器 ,而上述三个服务器下马有yahoo.com、amazon.com、pbs.org、poly.edu等DNS服务器

    DNS服务器递归查询和迭代查询

 从浏览器到本地DNS服务器属于递归查询,而DNS服务器之间属于迭代查询。

  • 建立TCP连接
    三次握手
    1、 client ----{发送SYN报文}syn=1 seq=x(发送报文序号为X)-->server   === 客户端进入SYN_SEND状态,等待服务器确认
    2、server ---{发送syn+ack报文}syn=1 ack=x+1(确认序号为X+1)seq=y(发送报文序号)-->client === 服务器进入SYN_RECV转态
    3、client ---{发送报文ack}ack=y+1(确认序号为Y+1) seq=z(发送报文序号为Z)-->server === 客户端和服务器都进入ESTABLISHED状态,完成TCP三次握手。

为啥是三次握手而不是两次,四次呢?
1、为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误
2、为了解决“网络中存在延迟的重复分组”的问题
 

“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
谢希仁著《计算机网络》

  • 浏览器发送HTTP请求报文,服务器返回HTTP响应报文
    http报文包括:请求报头(请求方法、目标地址、遵循的协议)、请求主体
    注意:浏览器只能发送get、post的方法,而打开网页使用的是get方法
    请求网址:http://www.baidu.com/
    请求方法:GET
    远程地址:IP
    状态码:200 OK
    Http版本: HTTP/1.1
    请求头:。。。
    响应头:。。。
    注意:响应头有一个Set-Cookie:"PHPSESSID=c882giens9f7d3oglcakhrl994; path=/",说明浏览器没有关于这个网站的cookie信息.而第二次发请求的时候,请求头包含了第一次响应的cookie信息。
    Cookie用来保存一些有用的信息:1、如果首次访问,会提示服务器建立用户缓存信息2、如果不是,则利用cookies对应的键值,找到相应的缓存,缓存里面存放着用户名、密码和一些用户信息。

    通过get请求,和服务器响应,可以将服务器上的目标文件传输到浏览器进行渲染。
  • 渲染页面
    客户端拿到服务器端传输过来的文件,首先查看Response header,根据不同的状态码,做不同的事。如果响应资源进行了压缩(比如gzip),还需要进行解压。然后对响应资源做缓存。接下来,找到HTML和MIME文件,通过MIME文件,浏览器知道用页面渲染引擎来处理HTML文件。
    a、浏览器会解析html源码,然后创建一个DOM树。
    在DOM树中,每一个HTML标签都有一个对应的节点,并且每一个文本都有一个对应的文本节点。
    b、浏览器解析css代码,计算出最终的样式数据(将任何尺寸值到减少三个可能之一:auto px 百分比),形成CSS对象模型CSSOM
    忽略非法样式。 按照浏览器默认设置--用户设置--外链样式--内联样式--html中的style样式顺序进行渲
    c、利用dom和cssom构建一棵渲染树(rendering tree)
    rendering tree会忽略不学渲染的元素(head display:none)
    d、浏览器根据渲染树直接把页面绘制到屏幕上

浏览器容错进制

你从来没有在浏览器看过类似"语法无效"的错误,这是因为浏览器去纠正错误的语法,然后继续工作。

事件

当整个解析的过程完成以后,浏览器会通过DOMContentLoaded事件来通知DOM解析完成。

渲染堵塞

(栗子:当遇到script标签时,DOM构建暂停,直到脚本完成执行,再继续构建DOM树;当JS依赖CSS时,而CSS未被加载和构建,JS就会延迟脚本执行,直到CSS RULES被构建。)

CSS会堵塞JS执行

JS会堵塞后面的DOM解析

原则:

CSS资源排在JS资源的前面

JS放在HTML的底部,也就是</body>的前面

如果要改变阻塞模式,可以使用 defer 与 async

 

布局绘制

合成渲染层

回流重绘

 

浏览器编译执行
注:浏览器对同一域名的并发连接数是有限的,通常为 6 个。

附:https://blog.csdn.net/qq_39039128/article/details/104734337

参考:https://zhuanlan.zhihu.com/p/80551769

 

 

HTML资源加载顺序是什么?script标签的defer和async属性有什么作用?

html资源加载是从上至下的

  1. dom加载到link
    dom和css的加载时并行的。当css加载时,dom也在加载构建。当css遇到img等标签时,会向浏览器发送一个请求后,继续加载。等资源回来后,再添加在dom相应的位置。
  2. dom加载script
    dom和js不可以并行加载。当加载js时,遇到dom构建,dom构建就会暂停,直到js脚本执行完成才开始构建。当dom和js加载时,会将所有的js文件加载完做才能继续dom的加载。倘若js文件太大,则可能导致页面显示滞后,出现“假死”的状态,这叫做“堵塞效应”,非常不好的用户体验。所以js的文件开头一般需要window.οnlοad= function(){}或者$(document).ready(function(){})或者(function(){}()),就是为了让dom加载完再执行js。这样就不会出现找不到dom节点的问题了。
    js堵塞资源加载的原因:浏览器防止js修改dom树,需要重新构建dom树的情况出现。
  3. 解决办法
    前提:js是外部脚本
    设置defer="true",dom和js可以并行加载,待页面加载完再执行js,不存在堵塞。
    设置async="true",js是异步加载的,不依赖其他js和css,但是无法保证js文件的加载顺序,不存在堵塞,但是有跟dom并行的效果。
    同时使用defer和async,defer会失效。
    将script放在body标签后,就不会冲突了。

preview

 

请说出静态资源请求的优化措施?是否用过“雪碧图”和iconfont?

  1. 不请求 cache

    ·尽量使用公共资源,设置缓存,不重新请求资源
    ·使用pwa的离线加载
    ·避免加载不存在的路径,避免耗费性能。(link的href,script的src)
    ·业务允许的情况下,做某些降级。例如弱网(2G、unknown)优先使用缓存。
    ·预解析DNS,浏览器提前获取静态资源的IP地址,避免请求时再发起DNS解析请求。
     <meta http-equiv="x-dns-prefetch-control" content="on"><link rel="dns-prefetch" href="//cdn.domain.com">
    ·尽量不携带cookie(减少1kb)
    ·不做页面重定向,页面重定向延长页面内容返回的等待时长,一次重定向大约需要200ms不等的时间开销。
     
  2. 合并请求 combo
    ·cdn的combo技术合并资源
    <script src="//cdn.domain.com/js/??a.min.js,b.min.js">
    --合并拆分资源--
    ·使用webpack、rollup打包,打包js、打包图片到js(内嵌base64),生成雪碧图,甚至将项目打包成一个html(1kb)的文件
    ·拆分就是将开发使用的库,单独剥离开来,以公共资源引入
    ·将过大的文件拆分成多个小文件,避免单个资源耗时过大
  3. 压缩资源
    ·前端打包压缩
    ·服务器打包压缩zip
    ·图片压缩(tiny)
    ·尽可能是html文件打包在1kb以内,使html的内容请求在一个RTT内请求完成,最高限度地提高html载入速度。通常情况下,tcp网络的最大传输单位是1500B
  4. 静态资源分域存放
    从不同域名请求资源。浏览器针对同一域请求数量要控制在6以内(并发数量),超过可能会造成堵塞。如果资源来自不同的域,可以增大并行请求和下载速度。
  5. 延迟、异步、预加载、懒加载
    ·非首屏资源,使用defer或者async
    ·多屏页面,使用滚动加载
    ·首屏加载后可能会使用到的资源,在首屏加载完成后加载
    ·按需加载,执行的时候再加载
  6. 参考https://www.jianshu.com/p/b114f60fce7a

如何利用浏览器的缓存机制?

(参考:https://www.jianshu.com/p/54cc04190252)

 

 

什么是SEO?如何优化?

seo就是搜索引擎优化。

  1. 提供页面加载速度
    能使用css解决就不用背景图片;图片尽量压缩大小;图片的多个小icon可以制作成雪碧图,通过定位来展示;减少http的请求,加快页面加载的速度
  2. 结构、行为、表现的分离
    使页面加载过慢的一个重要原因是:将css和js全部堆积在html上
    可以使用外链引入来加快速度。
    css放在head里面,js放在body的最下方
  3. 优化网站分级结构
    使用面包屑导航,避免小蜘蛛迷路。最好每个页面都单独加sitemap,将网站结构一目了然地展示给小蜘蛛,更有利于小蜘蛛爬取信息
  4. 集中网站权重
    小蜘蛛分配到页面的权重是一定,这些权重将平均分配到a链接。为了集中网站权重,可以使用“rel=nofollow”这个属性,告诉小蜘蛛,无须爬取该目标页,将权重分配给其他链接。
  5. 文本强调标签的使用
    使用strong标签
  6. H标签的使用
    使用h1时,一个页面最多只能有一个,因为它是自带权重的,一般放页面的标题(首页的logo也可以加h1标签)
  7. 图片alt属性的使用
    在图片没加载出来是,可以使用alt属性的文字代替,有利于小蜘蛛抓取信息
  8. a标签的title属性的使用
    在不影响页面功能的情况下,a标签加上title属性,有利于小蜘蛛抓取信息
  9. 为图片指定宽高
    在页面加载时,浏览器会为图片留下既定的位置,图片下面的代码可以直接下载而不用等待,提高并行下载速度,提高页面加载速度。
  10. 启用keep-alive属性
    keep-alive---长连接。在没有设置此属性时,浏览器向服务器请求的connection是即连即断的。设置后,这个连接可以保持一段时间,提高页面加载速度。
  11. 使用浏览器缓存
    为一些不经常变化的文件设置一个相对较长的过期时间,用户访问网站时,会缓存这些文件,下次请求时,缓存的文件不用再向服务器发送http请求了。减少http请求,提高页面加载速度。
  12. 启用gzip压缩
    开启gzip压缩后,网站服务器传输数据前,经过了压缩;传输到浏览器时,数据会被解压缩,从而浏览器正常显示。但是压缩率提高了很多,并且搜索引擎对网站抓取量也提升了很多。

     

SPA(single page application,单页应用)和传统网页相比的优缺点是什么?

优点:

  • 用户体验好、快,内容的改变不需要加载整个页面。避免不必要的跳转和重复渲染。
  • 服务端压力小
  • 前后端职责分离,架构清晰。前端负责交互逻辑,后端负责数据处理

缺点:

  • 初次加载耗时长:加载页面时统一加载js、css文件,部分页面按需加载
  • 前进后退路由管理:一个页面显示所有的内容,不能使用浏览器的前进后退功能
  • SEO难度大:所有的内容在同一页面动态替换的,SEO难度大

 

跨域的定义是什么?

(参考:https://segmentfault.com/a/1190000011145364

广义的跨域

一个域下的文档或脚本试图去请求另一个域下的资源

  • 资源跳转:<a>  重定向 表单提交
  • 资源嵌入:<script><link><frame><img>等dom标签,还有样式background:url() 、 @frot-face()等文件外链
  • 脚本请求:ajax js或dom对象的跨域请求

狭义的跨域(通常是讲这个)---浏览器同源策略

如果缺少同源策略,浏览器很容易受到xss、csrf的攻击;

同源指的是“协议、域名、端口”三个相同;其中有一个不一样就是跨域,即使两个域名指向同一个ip也是跨域

同源限制以下几种行为:

  • 无法访问cookie、localstorge、indexdb
  • 无法获得js和dom对象
  • 无法发送ajax请求
     

请说出常用的跨域解决方案

  • jsonp
    html下可以通过相应的标签从不同的域名加载静态资源
    1、原生实现
    <script>
        var script
        script.type = 'text/javascript'
        script.src = "http://kyfeng.com?name=ky&callback=handleCallback"
        document.head.appendChild(script)
    
        //返回回调时执行函数
        function handleCallback(res) {
            console.log(JSON.stringfy(res))
        }
    </script>
    
    //服务器返回以下(返回时即执行全局函数)
    handleCallback({"status":true, "name":"ky"})

    代码片段:


    2、jquery ajax

    $.ajax({
        type:'get',
        url:'http://kyfeng.com?name=ky',
        dataType:'jsonp',
        jsonCallback:'handleCallback',
        data:{}
    })

    3、vue.js
     

    this.$http.jsonp('http://kyfeng.com?name=ky',{
        params:{},
        jsonp:'handleCallback'
    }).then(res=>{
        console.log(res)
    })

    jsonp缺点:只能使用get请求

  • document.domain+iframe

    用于主域相同,子域不相同
    原理:两个页面都通过js强制设置document.domain为基础主域,实现同域
    //父窗口 http://www.domain.com/a.html
    
    <iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
    document.domain = "domain.com"
    var user = 'domain'
    
    
    
    //子窗口 http://child.domain.com/b.html
    
    document.domain = "domain.com"
     //获取父域变量
    console.log(window.parent.user)

     

  • location.hash+iframe

    原理:不同域之间只能通过iframe的location.hash进行传值,只有同域才能通过js进行通信

    a域想和b域通信,需要借助另一页面。 (A和C同域,B不同域)
    A.html ----hash--- > B.html ---hash--->C.html---window.parent.parent执行A的callback--->A.html
    //A.html  http://www.domain1.com/a.html
    <iframe id="iframe" src="http://www.domain2.com/b.html">
    <script>
        var iframe = document.getElementById('iframe')
        setTimeout(function(){
             iframe.src = iframe.src + '#name=domain'
        },1000)
            
        function onCallback(res) {
            console.log('接收的数据',res)
        }
    
    </script>
    
    
    //B.html  
    <iframe id="iframe" src="http://www.domain1.com/c.html">
    <script>
        var iframe = document.getElementById('iframe')
        window.onhashchange = function() {
            iframe.src = iframe.src + location.hash
        }
    </script>
    
    //C.html
        window.onhashchange = function() {
            window.parent.parent.onCallback('hello'+ location.hash.replace('#name=', ''))
        }
    

     

  • window.name+iframe

    window.name在不同页面(不同域名)加载后依然存在,并且支持设置很长的name(2MB)
     
    //a.html http://www.domain1.com/a.html
    function proxy(url, callback) {
        let state = 0
        let iframe = document.creatElement('iframe')
        iframe.src = url
        
        iframe.onload = function() {
            if(state === 1) {
                //读取同域window.name的数据
                callback(iframe.contentWindow.name)
                destoryFrame()
            }else if(state === 0) {
                //加载跨域页成功后,切换同域代理
                iframe.contentWindow.location = 'http://www.domain1.com/proxy.html'
                state = 1
            }
        }
        document.body.appendChild(iframe)
        function destoryFrame() {
            iframe.contentWindow.document.write('')
            iframe.contentWindow.close()
            document.body.removeChild(iframe) 
        }        
    }
    
    proxy('http://www.domain2.com/b.html', function(res) {
        console.log(res)
    })
    
    
    
    //proxy.html http://www.domain1.com/proxy.html
    //中间代理页
    
    //b.html  http://www.domain2.com/b.html
    
        window.name = 'this is domain2's name'
    • postmessage (h5的api)
      可解决的问题:
      1、页面与新打开的页面数据传递
      2、多页面的消息传递
      3、页面嵌套iframe的消息传递
      4、以上三种情形的跨域数据传递

      用法:postMessage(data【-只支持字符串 最好使用JSON.stringify序列化一下】, origin【协议+主机+端口 | * | 同源设置为 / 】)
      //a.html http://www.domain1.com/a.html
      <iframe id="iframe" src="http://www.domain2.com/b.html"></iframe>
       <script>
           const iframe = document.getElementById('iframe')
           iframe.onload = function() {
                const data = {
                  name:'ky'
                 }
               iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com')   
           }
          window.addEventListener('message', funtion(res) {
              console.log(res)
          },false)
              
      </script>
      
      
      //b.html http://www.domain2.com/b.html
          window.addEventListener('message', funtion(e) {
              console.log('收到a传过来的数据',e.data)
              const data = JSON.parse(e.data)
              if(data) {
                  data.number = 12
              }
              window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com')
          },false)
      

       

  • 跨域资源共享CORS
    **********前端***********
    //原生设置
    xhr.withCredential = true //是否带cookie
    
    //jquery设置
    $.ajax({
        xhrFields:{
            withCredential: true
        },
        crossDomain: true // 让请求头中包含跨域的额外信息,但不会包含cookie
    })
    
    //vue设置
    1)axios
    axios.defaults.withCredentials = true
    2)vue-resource
    Vue.http.options.credentials = true
    
    *********后端************
    //Node
    
     res.header('Access-Control-Allow-Credentials', true)
     res.header('Access-Control-Allow-Origin', 'http://localhost:3001')
     res.header('Set-Cookie', 'l=a123456;Path=/;Domain=localhost:3001;HttpOnly') //HttpOnly的作用:让js无法读取cookie  
    
    

     

  • nginx代理跨域

    1、nginx配置解决iconfont跨域(浏览器跨域访问js、css、img等静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器加入以下配置)
    location / {
        add_header Access-Control-Allow-Origin *;
    }

    2、nginx反向代理接口跨域
    跨域原理:同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器调用HTTP接口这是使用HTTP协议,不会执行
    JS脚本,不需要同源策略,也就不存在跨域问题。


     

    #proxy服务器
    server {
        listen       81;
        server_name  www.domain1.com;
    
        location / {
            proxy_pass   http://www.domain2.com:8080;  #反向代理
            proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
            index  index.html index.htm;
    
            # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
            add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
            add_header Access-Control-Allow-Credentials true;
        }
    }

     

  • nodejs中间件跨域
    1)非vue框架跨域 
    node + express + http-proxy-middleware搭建一个proxy的服务器
    代码示例:
    //前端
    <script>
            var xhr = new XMLHttpRequest();
            // 前端开关:浏览器是否读写cookie
            xhr.withCredentials = true;
            // 访问http-proxy-middleware代理服务器
            xhr.open('get', 'http://localhost:3001/login?user=admin&callback=onCallback', true);
            xhr.send();
            function onCallback(res) {
                console.log(res)
            }
    </script>
    
    //自己的服务器 3001
    const express = require('express')
    const app = express()
    const path = require('path')
    const proxy = require('http-proxy-middleware')
    
    app.use('/', proxy.createProxyMiddleware({
         // 代理跨域目标接口
         target: 'http://localhost:3000',
         changeOrigin: true,
         // 修改响应头信息,实现跨域并允许带cookie
         onProxyRes: function(proxyRes, req, res) {
             res.header('Access-Control-Allow-Origin', 'http://localhost:3001');
             res.header('Access-Control-Allow-Credentials', 'true');
         },
         // 修改响应信息中的cookie域名
         cookieDomainRewrite: 'http://localhost:3001'  // 可以为false,表示不修改
    }))
    
    
    app.use(express.static(path.join(__dirname, 'www')))
    
    app.listen(3001, function(err) {
        if(err) {
            throw new Error('监听失败', err)
        }
        console.log('服务器开启成功,端口为3001')
    })
    
    //3000的服务器
    const express = require('express')
    const app = express()
    const path = require('path')
    
    app.get('/login', function(req, res) {
        console.log(req.query)
        const { user, callback } = req.query 
        const result = callback+"("+JSON.stringify({
            "status": true,
            user
        })+")"
         // 向前台写cookie
        res.header('Set-Cookie', 'l=a123456;Path=/;Domain=localhost:3000;HttpOnly') //HttpOnly的作用:让js无法读取cookie  
        res.status(200).send(result)
    })
    
    app.listen(3000, function(err) {
        if(err){
            throw new Error('监听失败', err)
        }
        console.log('服务器开启成功,端口为3000')
    })
    
    vue框架跨域(node + webpack + webpack-dev-server代理接口跨域)
    webpack-dev-server----页面渲染服务和接口代理服务
    module.exports = {
        entry: {},
        module: {},
        ...
        devServer: {
            historyApiFallback: true,
            proxy: [{
                context: '/login',
                target: 'http://www.domain2.com:8080',  // 代理跨域目标接口
                changeOrigin: true,
                secure: false,  // 当代理某些https服务报错时用
                cookieDomainRewrite: 'www.domain1.com'  // 可以为false,表示不修改
            }],
            noInfo: true
        }
    }
  • websocket跨域
    websocket protocol是h5一种新协议,实现浏览器和服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
    原生 websocket api使用不方便,我们使用socket.io,它很好地封装了websocket接口,提供了更简单、灵活的接口,也对不支持websocket的浏览器提供了兼容。
     
        <div>user input:<input type="text"></div>
        <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
        <script>
            const socket = io('http://localhost:3000')
    
            // 连接成功处理
            socket.on('connect', function() {
                console.log('connecting')
                // 监听服务端消息
                socket.on('message', function(msg) {
                    console.log('data from server: ---> ' + msg); 
                })
    
                // 监听服务端关闭
                socket.on('disconnect', function() { 
                    console.log('Server socket has closed.')
                })
            })
    
            document.getElementsByTagName('input')[0].onblur = function() {
                socket.send(this.value);
            }
        </script>
    const http = require('http')
    const socket = require('socket.io')
    
    const server = http.createServer(function(req, res) {
        res.writeHead(200, {
            'Content-type': 'text/html'
        })
        res.end()
    })
    
    server.listen(3000, function(err) {
        if(err){
            throw new Error('监听失败', err)
        }
        console.log('服务器开启成功,端口为3000')
    })
    
    // 监听socket连接
    socket.listen(server).on('connection', function (client) {
        //接收信息
        client.on('message', function (msg) {
            client.send('hello:' + msg)
            console.log('data from client: --->' + msg)
        })
    
        // 断开处理
        client.on('disconnect', function () {
            console.log('Client socket has closed')
        })
    })
  •  

  •  

什么是CSRF攻击?如何预防?

(参考:https://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html)

  • CSRF:跨站请求伪造。攻击者盗用用户身份,发送恶意请求,造成个人隐私泄露以及财产安全问题。
  • 2009040916453171.jpg
  •  
  • 要完成一次CSRF,受害者必须完成:
    1、登录并信任网站A,并且浏览器生成cookie
    2、在未登出网站A的情况下,访问危险网站B
  • CSRF源于web的隐式身份验证机制,web的身份验证机制可以识别出请求是来自某一用户的浏览器,但无法保证请求是经用户批准发送的。

防御机制(可从客户端和服务端两方面着手,但是服务端防御效果比较好,现在一般csrf防御都是在服务端进行)---在客户端页面增加伪随机数

  1. 直接受POST请求
  2. 验证码:需要用户互动,简单有效防御CSRF攻击
  3. 验证Referer:之前的网址一定保留在新页面的Referer属性中。通过检查Referer,可以判断请求是合法还是非法。但是服务器不是任何时候都接收到Referer;Referer Check一般用于监控CSRF攻击的发生,而不是抵御攻击
  4. Token:目前主流的做法是使用Token防御csrf攻击
    1、Token要足够随机,使攻击者无法预测
    2、Token是一次性的,即每次请求成功后要更新
    3、Token要具有保密性,敏感操作使用POST,防止Token出现在URL中

什么是XSS攻击?如何预防?

  • XSS是跨站脚本攻击,攻击者向有XSS漏洞的网站,注入恶意的HTML片段;当用户浏览该网站时,该HTML代码会自动执行,已达到攻击的目的;盗取用户的Cookie、破坏页面结构、重定向到其他网站等。
  • 持久型XSS:对客户端攻击的脚本植入服务器,所有正常访问的用户都会受到XSS脚本的攻击
  • 非持久型XSS:对一个页面的URL的某个参数做文章,把精心打包好的恶意脚本包装在URL参数中,再将该URL发布到网上,骗去用户访问,从而进行攻击
  • 非持久型XSS安全威胁小,只要服务端调整业务代码进行过滤,这段XSS代码就会失效;持久型XSS威胁大,有时服务端要删好几张表,查询很多数据库才能把恶意代码删除

防御措施(防御XSS攻击最简单最直接的方法就是:过滤用户输入。

  1. 如果不需要输入HTML,可以对用户输入的内容进行HTML转义
  2. 如果需要输入HTML,将用户的输入使用HTML解析库进行解析,并且获取其中的内容。然后根据用户原有的标签重构HTML元素树。在构建的过程中,所有的标签、属性都只从白名单中拿取。

 

请介绍一下cookies

 cookielocalStorgesessionStorgesession
存储位置客户端客户端客户端服务端
特点随请求头每次提交不随请求头提交,长时保存不随请求头提交,页面关闭失效安全
跨页可跨页,不可跨域可跨页,不可跨域不可跨页,不可跨域可跨页,不可跨域
大小不超过4k可达5M可达5M 

                                                           key-value存储,同域名可用,不可跨浏览器

  • cookie包括name、expires、domain、path等要素
  • 设置cookie: document.cookie = "name="+name+";expires="+new Date().toUTCString()+";domain="+domain+";path="+path
  • 读取cookie: const data = document.cookie //获取对应页面的cookie

解析cookie

var name = "jack"
var pwd = "123"  
var now = new Date()
now.setTime(now.getTime() +1 * 24 * 60 * 60 * 1000)
var path = "/"
var document = {} //模拟一下
document.cookie = "name=" + name + ";expires=" + now.toUTCString() + ";path=" + path 
function getKey(key) {
   const data = document.cookie
   const findStr = key + '='
   const index = data.indexOf(findStr)
   if(index === -1) 
    return null
   const subStr = data.substring(index + findStr.length)
   const subIndex = subStr.indexOf(';')
   if(subIndex === -1)
    return subStr
    return subStr.substring(0, subIndex)
}
const result = getKey('name')
console.log(result)

正则
 

function getKey(key) {  
    return JSON.parse("{\"" +document.cookie.replace(/;\s+/gim, "\",\"").replace(/=/gim, "\":\"") + "\"}")[key];  
}  
  • 清除cookie
    document.cookie = "name="+" ;expires="+new Date().toUTCString()

请说出2个以上post请求的数据格式

  • application/json

  • text/plain

  • application/x-www-form-urlencoded

  • multipart/form-data

get和post的区别?还有其他method吗?

  1. get不安全,请求参数拼接在url。post对于用户来说是不可见的。
  2. get数据量小,受url长度限制。post数据量较大,一般被默认不受限制。
  3. get限制form数据集的值为ASCII字符。post支持整个ISO10646字符集。
  4. get执行效率比post好。get是form提交的默认方法。

如何用Promise改造ajax?

Promise,就是一个对象,用来传递异步操作的信息。

const ajaxPromise = params => {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()
        xhr.open(params.type||'get', params.url, true)
        xhr.send(params.data||null)
        xhr.onreadystatechange = ()=>{
            if(xhr.readyState === 4 ) {
                if(xhr.status === 200){
                    resolve(xhr.responseText)   
                }else {
                    reject(xhr.responseText)
                }
            }
        }
    })
}

Promise除了then,还有什么方法?

catch resolve reject all race

 

如何实现多个异步请求全部完成后,再执行某操作?

Promise.all([p1, p2, p3]) 批量执行 现多个异步请求全部完成后,再执行某操作

Promise.race() 类似于Promise.all() ,区别在于它有任意一个完成就算完成

是否用过async/await?

async function fn() {

   await f1() //同步

  console.log('xx') //异步

}

function f1(){}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值