React

1.key的作用

key帮助React识别哪些项目已更改,已添加或已删除。也因此可以高效的更新虚拟DOM列表,key值是用来判断 VDOM 元素项的唯一依据

  • key相同,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新。
  • key值不同,则react先销毁该组件(有状态组件的componentWillUnmount会执行),然后重新创建该组件(有状态组件的constructor和componentWillUnmount都会执行)

2.vdom的更新策略diff

3.setState同步异步?

在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理)或者钩子函数中,调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

原因:在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

class App extends React.Component {
  state = { val: 0 }

  componentDidMount() {
    this.setState({ val: this.state.val + 1 })
    console.log(this.state.val) // 0 在钩子函数中不会立即更新

    this.setState({ val: this.state.val + 1 })
    console.log(this.state.val) // 0 在钩子函数中不会立即更新

    setTimeout(_ => {
      this.setState({ val: this.state.val + 1 })
      console.log(this.state.val); // 2 这里会立即更新,并且由于setstate批量更新测量,componentDidMount的两次setstate只会取最后一次,即1

      this.setState({ val: this.state.val + 1 })
      console.log(this.state.val) // 3 同上
    }, 0)
  }

  render() {
    return <div>{this.state.val}</div>
  }
}

4.什么是错误边界

在 React 中,我们通常有一个组件树。如果任何一个组件发生错误,它将破坏整个组件树。没有办法捕捉这些错误,我们可以用错误边界优雅地处理这些错误。

错误边界有两个作用

  • 如果发生错误,显示回退UI
  • 记录错误

下面是ErrorBoundary类的一个例子。如果类实现了 getDerivedStateFromErrorcomponentDidCatch 这两个生命周期方法的任何一下,,那么这个类就会成为ErrorBoundary。前者返回{hasError: true}来呈现回退UI,后者用于记录错误。

export class ErrorBoundary extends React.Component {
    constructor(props) { 
        super(props); 
        this.state = { hasError: false }; 
     } 
     static getDerivedStateFromError(error) { 
         // Update state so the next render will show the fallback UI. 
         return { hasError: true }; 
     } 
     componentDidCatch(error, info) { 
        // You can also log the error to an error reporting service 
        console.log('Error::::', error); 
     } 
     render() { 
        if (this.state.hasError) { 
            // You can render any custom fallback UI               return <h1\>OOPS!. WE ARE LOOKING INTO IT.</h1\>; 
        } 
        return this.props.children; 
    } 
}

5.在构造函数调用super并将props作为参数传入的作用是啥?

在调用super()方法之前,子类构造函数无法使用this引用,ES6 子类也是如此。将props参数传递给super()调用的主要原因是在子构造函数中能够通过this.props来获取传入的props

传递 props

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    console.log(this.props);  // { name: 'sudheer',age: 30 }
  }
}

没有传递 props

class MyComponent extends React.Component {
  constructor(props) {
    super();
    console.log(this.props); // undefined
    // 但是 Props 参数仍然可用
    console.log(props); // Prints { name: 'sudheer',age: 30 }
  }

  render() {
    // 构造函数外部不受影响
    console.log(this.props) // { name: 'sudheer',age: 30 }
  }
}

6.新旧生命周期对比

Redux

Mobx

Webpack

1.webpack和gulp区别

gulp是基于任务和流的处理。放在以前比如我想用sass写css, coffee写js, 我必须手动的用相应的compiler去编译各自的文件,然后各自minify。这时候designer给你了两张新图片,好嘞,接着用自己的小工具手动去压缩图片。
后来前端人不能忍了,搞出个自动化这个流程的 Grunt/Gulp, 比如你写完代码后要想发布production版本,用一句gulp build就可以

rm掉 dist文件夹中以前的旧文件
自动把sass编译成css, coffee编译成js
压缩各自的文件,压缩图片,生成图片sprite 
拷贝minified/uglified 文件到 dist 文件夹

webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。

2.loader 的执行顺序为什么是后写的先执行

loader中采取compose的洋葱模型,内部采用reduceRight实现,因此是后写的先执行

function compose(...loaders){
    return function(arg){
        return loaders.reduceRight((res, cur) => {
            return cur(res)
        }, arg)
    }
}

3.常用的loader和plugins以及他们的区别

常见的loader
  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
  • url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试
  • image-loader:加载并且压缩图片文件
  • babel-loader:把 ES6 转换成 ES5
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
  • style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
  • eslint-loader:通过 ESLint 检查 JavaScript 代码
常见的plugins
  • define-plugin:定义环境变量
  • commons-chunk-plugin:提取公共代码
  • uglifyjs-webpack-plugin:通过UglifyES压缩ES6代码
不同的作用
  • Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非js文件的能力。
  • Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 针对loader结束后,在 Webpack 运行的生命周期中会广播出许多事件,它并不直接操作文件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
不同的用法
  • Loadermodule.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options
  • Pluginplugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。

3.webpack优化

优化Loader配置

由于loader对于文件的转换很耗时,所以需要让尽量少的文件被处理,通过修改test,use,include或者exclude配置来实现

module.exports = { 
    module : { 
        rules : [{
            //如果项目源码中只有 文件,就不要写成/\jsx?$/,以提升正则表达式的性能
            test: /\.js$/, 
            //babel -loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
            use: ['babel-loader?cacheDirectory'] , 
            //只对项目根目录下 src 目录中的文件采用 babel-loader
            include: path.resolve(__dirname,'src'),
        }],
    }
}
ts-loader优化

本质是通过配置ts-loader的transpileOnly: true 不进行类型检查来提高编译速度,而fork-ts-checker-webpack-plugin插件单独开一个进程进行ts的类型检查

优化resolve.modules

resolve.modules默认值是['node_modules'],webpack查找模块的机制和nodejs很类似,先从当前目录的node_modules下去找,找不到再去上一级../node_modules,以此类推。前端大部分项目node_modules都是在根目录,因此直接配置如下方式可以减少查找

 module.exports = {
        resolve: {
            modules: [path.resolve( __dirname,'node modules')] 
        },
    }
module.noParse

通过如下配置使得没有模块化的第三方库无需被解析


module.exports = {
    module: {
        noParse: /jquery/,
    }
};
使用happyPack

由于webpack是单线程处理,所以只能一个个处理任务。happyPack可以将任务拆分成多个分配给子进程并发处理,子进程都处理完了再通知主线程

const HappyPack = require('happypack')
    const os = require('os')
    const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })

    {
        test: /\.js$/,
        // loader: 'babel-loader',
        loader: 'happypack/loader?id=happy-babel-js', // 增加新的HappyPack构建loader
        include: [resolve('src')],
        exclude: /node_modules/,
    }
    
    plugins: [
        new HappyPack({
            id: 'happy-babel-js',
            loaders: ['babel-loader?cacheDirectory=true'],
            threadPool: happyThreadPool
        })
    ]
使用 ParallelUglifyPlugin压缩

webpack提供的UglifyJS只能单线程的一个个压缩js文件(压缩JS代码需要先把代码解析成用Object抽象表示的AST语法树,再去应用各种规则分析和处理AST,导致这个过程耗时非常大),而通过使用ParallelUglifyPlugin可以开启多个子进程并行使用UglifyJS压缩每个任务

使用 splitChunks 进行分包
tree-shaking

Tree Shaking 正常工作的前提是,提交给 Webpack 的 JavaScript 代码必须采用了 ES6 的模块化语法,因为 ES6 模块化语法是静态的,可以进行静态分析。
首先,为了将采用 ES6 模块化的代码提交给 Webpack ,需要配置 Babel 以让其保留 ES6 模块化语句。修改 .babelrc 文件如下:

  {
        'presets':[
            [
                'env',{ 
                    'module':false
                }
            ]
        ]
    }

第二个要求,需要使用UglifyJsPlugin插件。如果在mode:"production"模式,这个插件已经默认添加了,如果在其它模式下,可以手工添加它。

另外要记住的是打开optimization.usedExports。在mode: "production"模式下,它也是默认打开了的。它告诉webpack每个模块明确使用exports。这样之后,webpack会在打包文件中添加诸如/* unused harmony export */这样的注释,其后UglifyJsPlugin插件会对这些注释作出理解。

module.exports = {
    mode: 'none',
    optimization: {
        minimize: true,
        minimizer: [
            new UglifyJsPlugin()
        ],
        usedExports: true,
        sideEffects: true
    }
}

最关键的是要在package.json中的sideEffects配置,默认是true。即都是副作用,这样tree-shaking就不会起作用,需要改成false或者通过数组配置哪些文件有副作用。值得注意的是都设置为false的话
import './index.less'
这样的语句也是会被shaking掉,因此还需要在样式的loader中配置sideEffects:true

抛弃ua-device和Moment.js

没想到这个小小的库竟然会有这么大,不过据说这个库是目前能识别机型信息最准确的库,但是考虑到项目中只需要判断是不是微信和支付宝环境,必须要放弃使用了。

谷歌在github上有一个项目用来专门讨论如何去优化webpack

其中提到了使用date-fns来代替momentjs

效果如下:

并且使用date-fns也不需要在webpack中配置,可以说使用momentjs在webpack里面一顿操作猛如虎,不如直接使用date-fns

    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)

4.webpack工作流程

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
  3. 确定入口:根据配置中的 entry 找出所有的入口文件;
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译。利用babel转为Ast->遍历Ast->调用ImportDeclaration。找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
  5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
  7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

5.webpack的热更新是如何做到的?说明其原理?

6.Tree Shaking原理以及和dead code elimination(DCE)的区别

Dead Code 一般具有以下几个特征
  • 代码不会被执行,不可到达
  • 代码执行的结果不会被用到
  • 代码只会影响死变量(只写不读)

传统的编译型语言都是由编译器去除掉DC,而js是通过uglify插件去除

Tree Shaking

es6模块特点

  • 只能作为模块顶层的语句出现
  • import 的模块名只能是字符串常量
  • import binding 是 immutable的

ES6模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析,这就是tree-shaking的基础。

所谓静态分析就是不执行代码,从字面量上对代码进行分析,ES6之前的模块化,比如我们可以动态require一个模块,只有执行后才知道引用的什么模块,这个就不能通过静态分析去做优化。

正是基于这个基础上,才使得 tree-shaking 成为可能,这也是为什么 rollup 和 webpack 2 都要用 ES6 module syntax 才能 tree-shaking。

  • rollup只处理函数和顶层的import/export变量,不能把没用到的类的方法消除掉
  • javascript动态语言的特性使得静态分析比较困难

浏览器

1.浏览器打开一个tab需要多少个进程

浏览器从关闭状态进行启动,然后新开 1 个页面至少需要 1 个网络进程、1 个浏览器进程、1 个 GPU 进程以及 1 个渲染进程,共 4 个进程;后续再新开标签页,浏览器、网络进程、GPU进程是共享的,不会重新启动,如果2个页面属于同一站点的话,并且从a页面中打开的b页面,那么他们也会共用一个渲染进程,否则新开一个渲染进程。

最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。

  • 浏览器进程:主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
  • 渲染进程:核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
  • GPU 进程:其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。
  • 网络进程:主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
  • 插件进程:主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。

2.TCP三次握手四次挥手

建立TCP连接
  • 第一次握手:A把位码syn=1和seq number=随机数x的数据包发送给B,A进入SYN_SEND状态,等待B的确认;(B收到syn=1的数据包知道A要请求建立连接)
  • 第二次握手:B收到请求后要向A确认连接信息,发送位码syn=1,ack=1,ack number=x+1,seq number=随机数y这样的数据包,此时服务器进入SYN_RECV状态;
  • 第三次握手:A收到后检查ack number准确性(是否是x+1),ack是否是1,如果正确则发送ack number=y+1,ack=1。B收到后检查ack number准确性(是否是y+1),ack是否是1,正确的话客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

简言之,客户端先向服务端发送消息,证明了客户端的发送能力,服务端接受消息后向客户端发送,证明了服务端的接收和发送能力,最后客户端接收到消息向服务端告知,证明了客户端的接受能力。
完成了三次握手,客户端和服务器端就可以开始传送数据。

ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0。
TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1。
SYN(SYNchronization) : 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
FIN (finis)即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
关闭TCP连接
  • 第一次分手:主机1(可以使客户端,也可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
  • 第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;
  • 第三次分手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;
  • 第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

3.HTTPS的TCP握手

https的握手阶段相比http多了一个ssl/tls协议。
该协议有这三个作用:
(1) 所有信息都是加密传播,第三方无法窃听。
(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。
(3) 配备身份证书,防止身份被冒充。
ssl/tls协议的核心思想是采用公钥加密。客户端向服务器索要公钥,利用公钥对传输的信息加密,服务端收到密文后用私钥解密。
可是这个过程会产生两个问题
(1)如何保证公钥不被篡改?

解决方法:将公钥放在[数字证书](http://en.wikipedia.org/wiki/Digital_certificate)中。只要证书是可信的,公钥就是可信的。

(2)公钥加密计算量太大,如何减少耗用的时间?

解决方法:每一次对话(session),客户端和服务器端都生成一个"对话密钥"(session key),用它来加密信息。由于"对话密钥"是对称加密,所以运算速度非常快,而服务器公钥只用于加密"对话密钥"本身,这样就减少了加密运算的消耗时间。

因此ssl/tls协议的基本过程就是这样的
(1) 客户端向服务器端索要并验证公钥。
(2) 双方协商生成"对话密钥"。
(3) 双方采用"对话密钥"进行加密通信。
而前两步就是握手阶段。这其中涉及四次握手,且都是明文

客户端发出请求(ClientHello)

首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。

在这一步,客户端主要向服务器提供以下信息。

(1) 支持的协议版本,比如TLS 1.0版。

(2) 一个客户端生成的随机数,稍后用于生成"对话密钥"。

(3) 支持的加密方法,比如RSA公钥加密。

(4) 支持的压缩方法。

这里需要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。

对于虚拟主机的用户来说,这当然很不方便。2006年,TLS协议加入了一个Server Name Indication扩展,允许客户端向服务器提供它所请求的域名。

服务器回应(SeverHello)

服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。

(1) 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。

(2) 一个服务器生成的随机数,稍后用于生成"对话密钥"。

(3) 确认使用的加密方法,比如RSA公钥加密。

(4) 服务器证书。

除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。

客户端回应

客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。

如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。

(1) 一个随机数。该随机数用服务器公钥加密,防止被窃听。

(2) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

(3) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。

上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"。有了它以后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。

至于为什么一定要用三个随机数,来生成"会话密钥",dog250解释得很好:

"不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。

对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。

pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"

此外,如果前一步,服务器要求客户端证书,客户端会在这一步发送证书及相关信息。

服务器的最后回应

服务器收到客户端的第三个随机数pre-master key之后,计算生成本次会话所用的"会话密钥"。然后,向客户端最后发送下面信息。

(1)编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。

至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。

4.如何检测页面是否有卡顿

每秒中计算一次网页的 FPS 值,获得一列数据,然后分析。通俗地解释就是,通过 requestAnimationFrame API 来定时执行一些 JS 代码,如果浏览器卡顿,无法很好地保证渲染的频率,1s 中 frame 无法达到 60 帧,即可间接地反映浏览器的渲染帧率。

5.输入url后浏览器发生什么

DNS域名解析 -> tcp三次握手(https还有ssl/tls协议) -> 服务端响应客户端请求 -> tcp四次挥手 -> 浏览器渲染

查看

6.js代码在V8引擎中如果工作的?

查看

7.TCP和UDP的比较

UDP TCP
是否连接 无连接 面向链接
是否可靠 不可靠传输,不使用流量控制和拥塞控制 可靠传输,使用流量控制和拥塞控制
连接对象个数 支持一对一,一对多,多对一和多对多交互通信 只能一对一
传输方式 面向报文 面向字节流
首部开销 很小,仅8字节 20-60字节左右
适用场景 适用于实时应用(IP电话、视频会议、直播等) 适用于要求可靠传输的应用,例如文件传输
  • TCP向上层提供面向连接的可靠服务 ,UDP向上层提供无连接不可靠服务。
  • 虽然 UDP 并没有 TCP 传输来的准确,但是也能在很多实时性要求高的地方有所作为
  • 对数据准确性要求高,速度可以相对较慢的,可以选用TCP

8.HTTPS中间人攻击

  1. 服务器向客户端发送公钥。
  2. 攻击者截获公钥,保留在自己手上。
  3. 然后攻击者自己生成一个【伪造的】公钥,发给客户端。
  4. 客户端收到伪造的公钥后,生成加密hash值发给服务器。
  5. 攻击者获得加密hash值,用自己的私钥解密获得真秘钥。
  6. 同时生成假的加密hash值,发给服务器。
  7. 服务器用私钥解密获得假秘钥。
  8. 服务器用加秘钥加密传输信息

防范方法:

  1. 服务端在发送浏览器的公钥中加入CA证书,浏览器可以验证CA证书的有效性

9.介绍下oauth

详见阮老师博客


wens
269 声望4 粉丝