360前端星计划汇总(0409)

javascript从入门到放弃

一、各司其职
案例:关灯吃面
版本一:

light.onclick = function(evt) {
  if(light.style.backgroundColor !== 'green'){
    document.body.style.backgroundColor = '#000';
    document.body.style.color = '#fff';
    light.style.backgroundColor = 'green';
  }else{
    document.body.style.backgroundColor = '';
    document.body.style.color = '';
    light.style.backgroundColor = '';    
  }
}

有什么问题?
个人思考:js做了css的工作,并且给后期代码维护增加难度。

版本二:

lightButton.onclick = function(evt) {
  if(main.className === 'light-on'){
    main.className = 'light-off';
  }else{
    main.className = 'light-on';
  }
}

这个版本有什么改进?
个人思考:用css封装样式,js通过监测用户点击来改变样式。代码量也简单了,有利于后期维护。
其他思路:
版本三:可以全用css控制。

什么时候用版本二,什么时候用版本三?
版本二:在PC端
版本三:移动端

二、负责UI组件的设计
如何设计一个轮播图组件?
步骤1:结构设计

html
<div id="my-slider" class="slider-list">
  <ul>
    <li class="slider-list__item--selected">
      <img src="https://p5.ssl.qhimg.com/t0119c74624763dd070.png"/>
    </li>
    <li class="slider-list__item">
      <img src="https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg"/>
    </li>
    <li class="slider-list__item">
      <img src="https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg"/>
    </li>
    <li class="slider-list__item">
      <img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg"/>
    </li>
  </ul>
</div>
css
#my-slider{
  position: relative;
  width: 790px;
}

.slider-list ul{
  list-style-type:none;
  position: relative;
  padding: 0;
  margin: 0;
}

.slider-list__item,
.slider-list__item--selected{
  position: absolute;
  transition: opacity 1s;
  opacity: 0;
  text-align: center;
}

思考:
1.图片结构是一个列表型结构,所以主体用 ul
2.使用 css 绝对定位将图片重叠在同一个位置
3.轮播图切换的状态使用修饰符(modifier)
4.轮播图的切换动画使用 css transition

步骤2:API的设计

class Slider{
  constructor(id){
    this.container = document.getElementById(id);
    this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
  }
  getSelectedItem(){
    const selected = this.container.querySelector('.slider-list__item--selected');
    return selected
  }
  getSelectedItemIndex(){
    return Array.from(this.items).indexOf(this.getSelectedItem());
  }
  slideTo(idx){
    const selected = this.getSelectedItem();
    if(selected){ 
      selected.className = 'slider-list__item';
    }
    const item = this.items[idx];
    if(item){
      item.className = 'slider-list__item--selected';
    }
  }
  slideNext(){
    const currentIdx = this.getSelectedItemIndex();
    const nextIdx = (currentIdx + 1) % this.items.length;
    this.slideTo(nextIdx);
  }
  slidePrevious(){
    const currentIdx = this.getSelectedItemIndex();
    const previousIdx = (this.items.length + currentIdx - 1) % this.items.length;
    this.slideTo(previousIdx);  
  }
}

const slider = new Slider('my-slider');
setInterval(() => {
  slider.slideNext()
}, 3000)

步骤3:控制流设计
控制结构

<a class="slide-list__next"></a>
  <a class="slide-list__previous"></a>
  <div class="slide-list__control">
    <span class="slide-list__control-buttons--selected"></span>
    <span class="slide-list__control-buttons"></span>
    <span class="slide-list__control-buttons"></span>
    <span class="slide-list__control-buttons"></span>
  </div>

自定义事件

const detail = {index: idx}
const event = new CustomEvent('slide', {bubbles:true, detail})
this.container.dispatchEvent(event)

优化1:插件/依赖注入

class Slider{
  constructor(id, cycle = 3000){
    this.container = document.getElementById(id);
    this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
    this.cycle = cycle;
  }
  registerPlugins(...plugins){
    plugins.forEach(plugin => plugin(this));
  }
  getSelectedItem(){
    const selected = this.container.querySelector('.slider-list__item--selected');
    return selected
  }
  getSelectedItemIndex(){
    return Array.from(this.items).indexOf(this.getSelectedItem());
  }
  slideTo(idx){
    const selected = this.getSelectedItem();
    if(selected){ 
      selected.className = 'slider-list__item';
    }
    const item = this.items[idx];
    if(item){
      item.className = 'slider-list__item--selected';
    }

    const detail = {index: idx}
    const event = new CustomEvent('slide', {bubbles:true, detail})
    this.container.dispatchEvent(event)
  }
  slideNext(){
    const currentIdx = this.getSelectedItemIndex();
    const nextIdx = (currentIdx + 1) % this.items.length;
    this.slideTo(nextIdx);
  }
  slidePrevious(){
    const currentIdx = this.getSelectedItemIndex();
    const previousIdx = (this.items.length + currentIdx - 1) % this.items.length;
    this.slideTo(previousIdx);  
  }
  addEventListener(type, handler){
    this.container.addEventListener(type, handler)
  }
  start(){
    this.stop();
    this._timer = setInterval(()=>this.slideNext(), this.cycle);
  }
  stop(){
    clearInterval(this._timer);
  }
}

function pluginController(slider){
  const controller = slider.container.querySelector('.slide-list__control');
  if(controller){
    const buttons = controller.querySelectorAll('.slide-list__control-buttons, .slide-list__control-buttons--selected');
    controller.addEventListener('mouseover', evt=>{
      const idx = Array.from(buttons).indexOf(evt.target);
      if(idx >= 0){
        slider.slideTo(idx);
        slider.stop();
      }
    });

    controller.addEventListener('mouseout', evt=>{
      slider.start();
    });

    slider.addEventListener('slide', evt => {
      const idx = evt.detail.index
      const selected = controller.querySelector('.slide-list__control-buttons--selected');
      if(selected) selected.className = 'slide-list__control-buttons';
      buttons[idx].className = 'slide-list__control-buttons--selected';
    });
  }  
}

function pluginPrevious(slider){
  const previous = slider.container.querySelector('.slide-list__previous');
  if(previous){
    previous.addEventListener('click', evt => {
      slider.stop();
      slider.slidePrevious();
      slider.start();
      evt.preventDefault();
    });
  }  
}

function pluginNext(slider){
  const next = slider.container.querySelector('.slide-list__next');
  if(next){
    next.addEventListener('click', evt => {
      slider.stop();
      slider.slideNext();
      slider.start();
      evt.preventDefault();
    });
  }  
}


const slider = new Slider('my-slider');
slider.registerPlugins(pluginController, pluginPrevious, pluginNext);
slider.start();

还有再改进的空间–引入插件机制
有个问题:插件功能的修改不能影响到样式。

优化2:改进插件/模板化

class Slider{
  constructor(id, opts = {images:[], cycle: 3000}){
    this.container = document.getElementById(id);
    this.options = opts;
    this.container.innerHTML = this.render();
    this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
    this.cycle = opts.cycle || 3000;
    this.slideTo(0);
  }
  render(){
    const images = this.options.images;
    const content = images.map(image => `
      <li class="slider-list__item">
        <img src="${image}"/>
      </li>    
    `.trim());
    
    return `<ul>${content.join('')}</ul>`;
  }
  registerPlugins(...plugins){
    plugins.forEach(plugin => {
      const pluginContainer = document.createElement('div');
      pluginContainer.className = '.slider-list__plugin';
      pluginContainer.innerHTML = plugin.render(this.options.images);
      this.container.appendChild(pluginContainer);
      
      plugin.action(this);
    });
  }
  getSelectedItem(){
    const selected = this.container.querySelector('.slider-list__item--selected');
    return selected
  }
  getSelectedItemIndex(){
    return Array.from(this.items).indexOf(this.getSelectedItem());
  }
  slideTo(idx){
    const selected = this.getSelectedItem();
    if(selected){ 
      selected.className = 'slider-list__item';
    }
    let item = this.items[idx];
    if(item){
      item.className = 'slider-list__item--selected';
    }
    
    const detail = {index: idx}
    const event = new CustomEvent('slide', {bubbles:true, detail})
    this.container.dispatchEvent(event)
  }
  slideNext(){
    const currentIdx = this.getSelectedItemIndex();
    const nextIdx = (currentIdx + 1) % this.items.length;
    this.slideTo(nextIdx);
  }
  slidePrevious(){
    const currentIdx = this.getSelectedItemIndex();
    const previousIdx = (this.items.length + currentIdx - 1) % this.items.length;
    this.slideTo(previousIdx);  
  }
  addEventListener(type, handler){
    this.container.addEventListener(type, handler);
  }
  start(){
    this.stop();
    this._timer = setInterval(()=>this.slideNext(), this.cycle);
  }
  stop(){
    clearInterval(this._timer);
  }
}

const pluginController = {
  render(images){
    return `
      <div class="slide-list__control">
        ${images.map((image, i) => `
            <span class="slide-list__control-buttons${i===0?'--selected':''}"></span>
         `).join('')}
      </div>    
    `.trim();
  },
  action(slider){
    const controller = slider.container.querySelector('.slide-list__control');
    
    if(controller){
      const buttons = controller.querySelectorAll('.slide-list__control-buttons, .slide-list__control-buttons--selected');
      controller.addEventListener('mouseover', evt => {
        const idx = Array.from(buttons).indexOf(evt.target);
        if(idx >= 0){
          slider.slideTo(idx);
          slider.stop();
        }
      });

      controller.addEventListener('mouseout', evt => {
        slider.start();
      });

      slider.addEventListener('slide', evt => {
        const idx = evt.detail.index
        const selected = controller.querySelector('.slide-list__control-buttons--selected');
        if(selected) selected.className = 'slide-list__control-buttons';
        buttons[idx].className = 'slide-list__control-buttons--selected';
      });
    }    
  }
};

const pluginPrevious = {
  render(){
    return `<a class="slide-list__previous"></a>`;
  },
  action(slider){
    const previous = slider.container.querySelector('.slide-list__previous');
    if(previous){
      previous.addEventListener('click', evt => {
        slider.stop();
        slider.slidePrevious();
        slider.start();
        evt.preventDefault();
      });
    }  
  }
};

const pluginNext = {
  render(){
    return `<a class="slide-list__next"></a>`;
  },
  action(slider){
    const previous = slider.container.querySelector('.slide-list__next');
    if(previous){
      previous.addEventListener('click', evt => {
        slider.stop();
        slider.slideNext();
        slider.start();
        evt.preventDefault();
      });
    }  
  }
};

const slider = new Slider('my-slider', {images: ['https://p5.ssl.qhimg.com/t0119c74624763dd070.png',
     'https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg',
     'https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg',
     'https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg'], cycle:3000});

slider.registerPlugins(pluginController, pluginPrevious, pluginNext);
slider.start();

有问题:还是存在一些依赖,要进行模块化
优化3:组件模型抽象

class Component{
  constructor(id, opts = {name, data:[]}){
    this.container = document.getElementById(id);
    this.options = opts;
    this.container.innerHTML = this.render(opts.data);
  }
  registerPlugins(...plugins){
    plugins.forEach(plugin => {
      const pluginContainer = document.createElement('div');
      pluginContainer.className = `.${name}__plugin`;
      pluginContainer.innerHTML = plugin.render(this.options.data);
      this.container.appendChild(pluginContainer);
      
      plugin.action(this);
    });
  }
  render(data) {
    /* abstract */
    return ''
  }
}

class Slider extends Component{
  constructor(id, opts = {name: 'slider-list', data:[], cycle: 3000}){
    super(id, opts);
    this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
    this.cycle = opts.cycle || 3000;
    this.slideTo(0);
  }
  render(data){
    const content = data.map(image => `
      <li class="slider-list__item">
        <img src="${image}"/>
      </li>    
    `.trim());
    
    return `<ul>${content.join('')}</ul>`;
  }
  getSelectedItem(){
    const selected = this.container.querySelector('.slider-list__item--selected');
    return selected
  }
  getSelectedItemIndex(){
    return Array.from(this.items).indexOf(this.getSelectedItem());
  }
  slideTo(idx){
    const selected = this.getSelectedItem();
    if(selected){ 
      selected.className = 'slider-list__item';
    }
    const item = this.items[idx];
    if(item){
      item.className = 'slider-list__item--selected';
    }

    const detail = {index: idx}
    const event = new CustomEvent('slide', {bubbles:true, detail})
    this.container.dispatchEvent(event)
  }
  slideNext(){
    const currentIdx = this.getSelectedItemIndex();
    const nextIdx = (currentIdx + 1) % this.items.length;
    this.slideTo(nextIdx);
  }
  slidePrevious(){
    const currentIdx = this.getSelectedItemIndex();
    const previousIdx = (this.items.length + currentIdx - 1) % this.items.length;
    this.slideTo(previousIdx);  
  }
  addEventListener(type, handler){
    this.container.addEventListener(type, handler);
  }
  start(){
    this.stop();
    this._timer = setInterval(()=>this.slideNext(), this.cycle);
  }
  stop(){
    clearInterval(this._timer);
  }
}

const pluginController = {
  render(images){
    return `
      <div class="slide-list__control">
        ${images.map((image, i) => `
            <span class="slide-list__control-buttons${i===0?'--selected':''}"></span>
         `).join('')}
      </div>    
    `.trim();
  },
  action(slider){
    let controller = slider.container.querySelector('.slide-list__control');
    
    if(controller){
      let buttons = controller.querySelectorAll('.slide-list__control-buttons, .slide-list__control-buttons--selected');
      controller.addEventListener('mouseover', evt=>{
        var idx = Array.from(buttons).indexOf(evt.target);
        if(idx >= 0){
          slider.slideTo(idx);
          slider.stop();
        }
      });

      controller.addEventListener('mouseout', evt=>{
        slider.start();
      });

      slider.addEventListener('slide', evt => {
        const idx = evt.detail.index;
        let selected = controller.querySelector('.slide-list__control-buttons--selected');
        if(selected) selected.className = 'slide-list__control-buttons';
        buttons[idx].className = 'slide-list__control-buttons--selected';
      });
    }    
  }
};

const pluginPrevious = {
  render(){
    return `<a class="slide-list__previous"></a>`;
  },
  action(slider){
    let previous = slider.container.querySelector('.slide-list__previous');
    if(previous){
      previous.addEventListener('click', evt => {
        slider.stop();
        slider.slidePrevious();
        slider.start();
        evt.preventDefault();
      });
    }  
  }
};

const pluginNext = {
  render(){
    return `<a class="slide-list__next"></a>`;
  },
  action(slider){
    let previous = slider.container.querySelector('.slide-list__next');
    if(previous){
      previous.addEventListener('click', evt => {
        slider.stop();
        slider.slideNext();
        slider.start();
        evt.preventDefault();
      });
    }  
  }
};

const slider = new Slider('my-slider', {name: 'slide-list', data: ['https://p5.ssl.qhimg.com/t0119c74624763dd070.png',
     'https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg',
     'https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg',
     'https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg'], cycle:3000});

slider.registerPlugins(pluginController, pluginPrevious, pluginNext);
slider.start();

三、局部细节控制
案例一:逐渐消失的方块

block.onclick = function(evt){
  console.log('hide');
  evt.target.className = 'hide';
  setTimeout(function(){
    document.body.removeChild(block);
  }, 2000);
};

一直点击会报错
解决:
1.设置只点击一次

block.onclick = function(evt){
  block.onclick = null;
  console.log('hide');
  evt.target.className = 'hide';
  setTimeout(function(){
    document.body.removeChild(block);
  }, 2000);
};

个人思考:可以判断一下是否存在,存在才执行函数内容。

抽象出一个once函数:

function once(fn){
  return function(...args){
    if(fn){
      let ret = fn.apply(this, args);
      fn = null;
      return ret;
    }
  }
}

function foo(idx){
  console.log(`I'm called:${idx}`);
}

foo(0);
foo(1);
foo(2);

foo = once(foo);

节流函数:在一定时间内只执行一次,把多次合并为一次

function throttle(fn, time = 500){
  let timer;
  return function(...args){
    if(timer == null){
      fn.apply(this,  args);
      timer = setTimeout(() => {
        timer = null;
      }, time)
    }
  }
}

防抖函数:给每次事件间隔一定的时间来执行

function debounce(fn, dur){
  dur = dur || 100;
  var timer;
  return function(){
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, dur);
  }
}

同步变异步:

function consumer(fn, time){
  let tasks = [],
      timer;
  
  return function(...args){
    tasks.push(fn.bind(this, ...args));
    if(timer == null){
      timer = setInterval(() => {
        tasks.shift().call(this)
        if(tasks.length <= 0){
          clearInterval(timer);
          timer = null;
        }
      }, time)
    }
  }
}

function add(x, y){
  let sum = x + y;
  console.log(sum);
  return sum;
}

let consumerAdd = consumer(add, 1000);

let sum = 0;
for(let i = 0; i < 10; i++){
  consumerAdd(sum, i);
}

命令式编程:关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么。

switcher.onclick = function(evt){
  if(evt.target.className === 'on'){
    evt.target.className = 'off';
  }else{
    evt.target.className = 'on';
  }
}

声明式编程:以数据结构的形式来表达程序执行的逻辑。它的主要思想是告诉计算机应该做什么,但不指定具体要怎么做。

function toggle(...actions){
  return function(...args){
    let action = actions.shift();
    actions.push(action);
    return action.apply(this, args);
  }
}

switcher.onclick = toggle(
  evt => evt.target.className = 'off',
  evt => evt.target.className = 'on'
);

好处是:可以自由加功能。

函数式编程:即只关注做什么而不是怎么做。但函数式编程不仅仅局限于声明式编程。函数式编程最重要的特点是“函数第一位”,即函数可以出现在任何地方。

高阶函数:它们自身输入函数或返回函数。
如once、throttle、debounced、consumer、iterative

总结:
1.各司其职:JavaScript 尽量只做状态管理
2.结构、API、控制流分离设计 UI 组件
3.插件和模板化,并抽象出组件模型
4.运用过程抽象的技巧来抽象并优化局部 API

Web标准:前端的原力

一、Web标准
Web是World Wide Web(万维网)的简称。
1.http1.0到http1.1
长连接:不必设置Contention:keep-alive就可以默认保持持续连接,每一次TCP连接可以发送响应多次HTTP请求。
缓存处理:更多可供选择的缓存头来控制缓存策略。
错误状态码:新增24个,如409:资源冲突
host字段:用于判断服务器中具体访问的站点。
2.http1.1到http2.0
多路复用:其实是利用select函数阻塞多个IO操作,并对这些IO操作进行轮询检测,一旦数据准备好后,就可以通知线程进行真正的IO操作。期间如果数据未准备好,用户线程可以可以干其他事情的。
二进制分帧:
将请求和消息压缩成二进制的帧,每个帧由头部和数据部分组成。
使用二进制分帧可乱序发送,并重新组装。
对于二进制分帧还需要规定其权重值,进一步提高性能。
首部压缩:压缩首部数据,只发送修改部分的数据。
服务器推送:除了客户端主动请求外,服务器还可以向客户端主动进行推送。
3.BOM的对象
是浏览器对象模型,它提供了很多对象,用于访问浏览器的功能。
Window:网页中所有全局对象、变量和函数都暴露在这个对象上。
Screen:保存着客户端显示器的信息。
Location:通过location对象可以以编程方式操纵浏览器的导航系统。
location.href-- 返回或设置当前文档的URL
location.port – 返回URL中的端口部分。
location.reload() – 重载当前页面
History:提供了操纵浏览器历史记录的能力。
history.go() – 前进或后退指定的页面数;
history.back() – 后退一页
history.forward() – 前进一页
Navigator:对象提供关于浏览器的信息。
navigator.userAgent – 返回用户代理头的字符串表示
navigator.cookieEnabled – 返回浏览器是否支持cookie
4.DOM
是HTML和XML文档的编程接口。DOM表示由多层节点构成的文档,通过它开发者可以添加、删除和修改页面的各个部分。DOM现在是真正跨平台、语言无关的表示和操作网页的方式。
DOM1(DOM Level 1)主要定义了HTML和XML文档的底层结构。DOM2(DOM Level 2)和DOM3(DOM Level 3)在这些结构之上加入更多交互能力,提供了更高级的XML特性。
元素节点(Element),注释节点(Comment),文本节点(Text),文档节点(Document)

前端常用的HTTP知识

1.http在浏览器网络中的位置

http在应用层
tcp、udp在传输层
2.请求类型
Post、get、put、delete、options、head、trance、connect
get和post的区别:
Get:从服务器获取数据,传输的数据大小不能超过2kb,参数外露安全性低,发送一个tcp数据包,浏览器会把 header和data一并发送出去。
Post:向服务器提交数据,传输数据量可以比较大,安全性高,发送两个tcp数据包,浏览器先发送header,服务器响应100后 ,浏览器再发送data。
其他方法解释:
Put:用于修改数据
Delete:删除请求,响应200后只表示删除响应并不真正删除。
Options:用于检测允许的请求头。
简单请求是直接进行请求校验:get、post、head。
非简单请求是先进行OPTION校验,若白名单继续发送Ajax通信:put、delete。
Head:返回响应首部
Trance:跟踪请求路径
Connect:在客户端与服务器之间建立隧道,实行SSL和TLS协议加密。
3.状态码
类别 原因
1XX 请求正在处理
2XX 请求正常处理完毕
3XX 请求附带操作(重定向)
4XX 客户端请求错误
5XX 服务器错误

常用状态码:
101 切换协议,如:将 HTTP 协议切换为 WebSocket 协议
200:请求成功。
206 返回部分内容,如:大文件下载。
301:资源(网页等)被永久转移到其它URL。
302:请求的资源现在临时从不同的URI响应请求。
304:所请求的资源未修改,不返回任何资源。
400:前端提交数据的字段名称和字段类型与后台的实体没有保持一致,无法解析请求。
401:未授权,用户名和密码错误
403:无权限访问,请求被拒绝
404 : 请求的资源(网页等)不存在。
413 请求实体过大,如:服务端限制了上传的文件大小。
500 :内部服务器错误
502 作为网关或代理服务器时,上游服务器异常
504 作为网关或代理服务器时,上游服务器处理超时

4.url
受限字符:%/.#?;:$+@&= 以及非US-ASCⅡ字符集字符。

5.常用head
通用首部:表示一些通用信息,比如date表示报文创建时间,
请求首部:请求报文中独有的,如cookie,和缓存相关的如if-Modified-Since
响应首部:响应报文中独有的,如set-cookie,和重定向相关的location,
实体首部:用来描述实体部分,如content-type描述主题类型,content-Encoding描述主体的编码方式

6.cookie
用于保存用户登录信息,在浏览器和服务器端来回传递。4k存储。同源窗口中都是共享的。
对于安全性防范:
XSS(跨站脚本攻击)是指攻击者在返回的HTML中嵌入javascript脚本,为了减轻这些攻击,需要在HTTP头部配上,set-cookie。
CSRF攻击:攻击者盗用了用户的身份,以用户的名义发送了恶意请求。防范:使用验证码,使用token。

服务器则对应为 Session,基于 Cookie 存放用户信息
Cookie 有效期为 Session(随浏览器进程退出而失效)
7.Content-Type
标识返回内容的类型,标识提交数据的类型。
application/x-www-form-urlencoded
multipart/form-data
application/json
text/xml
8.性能优化
keep-alive
减少网络传输大小
缓存:
Last-Modified
ETag
Expires

强缓存和协商缓存
强缓存:
①cache-control: max-age=xxxx,public
客户端和代理服务器都可以缓存该资源;
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,如果用户做了刷新操作,就向服务器发起http请求
②cache-control: max-age=xxxx,private
只让客户端可以缓存该资源;代理服务器不缓存
客户端在xxx秒内直接读取缓存,statu code:200
③cache-control: max-age=xxxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,即使用户做了刷新操作,也不向服务器发起http请求
④cache-control: no-cache
跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,只有在强缓存失效了才走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端。
⑤cache-control: no-store
不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了。

协商缓存:

etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT

http2/http3:
http3:基于 QUIC 协议(UDP)

9.http的抓包工具/发包工具
Wireshark
Fiddler
Firebug for Firefox
Chrome 开发者工具
IE8+ 自带的开发者工具

telnet / curl
Fiddler *
Tamper for Firefox
Postman for Chrome *
Paw for OSX

发布了18 篇原创文章 · 获赞 6 · 访问量 6289

猜你喜欢

转载自blog.csdn.net/qinsangdilvzhi/article/details/105415598
今日推荐