HTTP协议、存储、Ajax

HTTP协议、存储、Ajax

前端数据交互与HTTP协议

前后端通信

HTTP协议、存储、Ajax_第1张图片

 



  
    
    初识前后端通信
  
  
    
  



  
    
    前后端通信的过程与概念解释
  
  
    
  



  
    
    前后端的通信方式
    
  
  
    慕课网

    

HTTP协议

初识 HTTP



  
    
    初识 HTTP
  
  
    
  

HTTP报文

HTTP协议、存储、Ajax_第2张图片

 



  
    
    HTTP 报文
  
  
    

HTTP方法



  
    
    HTTP 方法
  
  
    
  

HTTP状态码



  
    
    HTTP 状态码
  
  
    
  


本地储存

Cookoe

  • 浏览器储存数据的一种方式
  • 储存在用户本地,而不是储存在服务器上
  • 可以随着浏览器每次请求发送发送到服务器端

初始cookie



  
    
    初识 Cookie
  
  
    
  


cookie的基本用法

写入cookie

document.cookie = 'username=alex;max-age=5';
document.cookie = 'age=18;domain=.imooc.com;max-age=5';

读取cookie

document.cookie; //username=alex;age=18


  
    
    Cookie 的基本用法
  
  
    
  


Cookie

  • 名称( Name )和值( Value )

                创建 Cookie 时必须填写,其他属性可以使用默认值

                如果包含非英文字母,写入时要用 encodeURIComponent() 编写

                如果写入时编码,读取时要用 decodeURIComponent() 解码

  • 失效( 到期 )时间

                失效的 Cookie,会浏览器清除

                如果没有设置失效时间,默认会话结束后,Cookie会被清除

                想Cookie长时间存在,可以设置 Expires 或 Max-Age

                Expires 值为 Date 类型,表示具体什么时间过期

                Max-Age 值为数字,表示当前时间加多少秒后过期,单位是秒

                如果设置 Max-Age 的值0或负数,则 Cookie 会被删除

  •  Domain

                Domain 限定了访问 Cookie 的范围( 不同城下 )

                使用 JS 只能写入/读取当前域或父域的Cookie,无法写入/读取其他域的Cookie

  • Path

                Path 限定了访问 Cookie的范围( 同城不同路径下 )

                使用 JS 只能写入/读取当前路径和上级路径的 Cookie ,无法写入/读取其他路径的 Cookie

  • 当 Name、Domain、Path 这 3 个字段都相同的时候,才是同一个 Cookie
  • HttpOnly

                前端不能通过 JS 去设置一个 HttpOnly 类型的 Cookie,这种类型的 Cookie 只能是后端来设置

                只要是 HttpOnly 类型的,通过 document.cookie 是获取不到的,也不能修改

  • Secure

                Secure 限定了只有在使用了 https 而不是 http 的情况下才可以发送给服务器

  • Domain、Path、Secure 都要条件,还不能过期的 Cookie 才能随着请求发送到服务器端


  
    
    Cookie 的属性
  
  
    
  


cookie的封装

// 写入 Cookie
const set = (name, value, { maxAge, domain, path, secure } = {}) => {
  let cookieText = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;

  if (typeof maxAge === 'number') {
    cookieText += `; max-age=${maxAge}`;
  }

  if (domain) {
    cookieText += `; domain=${domain}`;
  }

  if (path) {
    cookieText += `; path=${path}`;
  }

  if (secure) {
    cookieText += `; secure`;
  }

  document.cookie = cookieText;

  // document.cookie='username=alex; max-age=5; domain='
};

// 通过 name 获取 cookie 的值
const get = name => {
  name = `${encodeURIComponent(name)}`;

  const cookies = document.cookie.split('; ');

  for (const item of cookies) {
    const [cookieName, cookieValue] = item.split('=');

    if (cookieName === name) {
      return decodeURIComponent(cookieValue);
    }
  }

  return;
};

// 'username=alex; age=18; sex=male'
// ["username=alex", "age=18", "sex=male"]
// ["username","alex"]

// get('用户名');

// 根据 name、domain 和 path 删除 Cookie
const remove = (name, { domain, path } = {}) => {
  set(name, '', { domain, path, maxAge: -1 });
};

export { set, get, remove };

cookie注意事项

  • 前后端都可以写入和获取 Cookie
  • 每个域名下的 Cookie 数量有限
  • 每个 Cookie 的储存容量跟小,最多只有4KB左右


  
    
    Cookie 的注意事项
  
  
    
  


localStorage

  • 浏览器储存数据的一种方式
  • 储存在用户本地,不会发送到服务器
  • 单个域名下的总大小有限制( 一般最大 5M 左右 )
  • setltem()

                localStorage.setItem(‘username’:‘alex’);

  • getltem()

                localStorage.getItem(‘username’)

  • removeltem() 

                 localStorage.removeltem(‘username’)

  • celar()

                 localStorage.celar(‘username’)

  • length

                 localStorage.length

初始localStrage



  
    
    初识 localStorage
  
  
    

localStorage的注意事项

  • localStorage 储存的数据、除非手动清除、否则永远存在
  • sessionStorage 储存的数据,当会话结束时就会被清除
  • localStorage 储存的键和值只能是字符串类型
  • 不同的域名不能共用 localStorage
  • IE及以下版本不支持 localStorage,IE8开始支持


  
    
    localStorage 的注意事项
  
  
    
  


Ajax & Fetch跨域请求

Ajax基础

初始Ajax



  
    
    初识 Ajax
  
  
    
  


Ajax基础用法

// 1.XMLHttpRequest
console.log(Ajax);

// Ajax 想要实现浏览器与服务器之间的异步通信,需要依靠 XMLHttpRequest,它是一个构造函数

// 不论是 XMLHttpRequest,还是 Ajax,都没有和具体的某种数据格式绑定

// 2.Ajax 的使用步骤
// 2.1.创建 xhr 对象
const xhr = new XMLHttpRequest();

// 2.2.监听事件,处理响应
// 当获取到响应后,会触发 xhr 对象的 readystatechange 事件,可以在该事件中对响应进行处理

xhr.addEventListener('readystatechange', () => {}, fasle);

xhr.onreadystatechange = () => {
    if (xhr.readyState !== 4) return;

    // HTTP CODE
    // 获取到响应后,响应的内容会自动填充 xhr 对象的属性
    // xhr.status:HTTP  200 404
    // xhr.statusText:HTTP 状态说明 OK Not Found
    if ((xhr.status >= 200) & (xhr.status < 300) || xhr.status === 304) {
        // console.log('正常使用响应数据');
        console.log(xhr.responseText);
    }
};

// readystatechange 事件也可以配合 addEventListener 使用,不过要注意,IE6~8 不支持 addEventListener
// 为了兼容性,readystatechange 中不使用 this,而是直接使用 xhr
// 由于兼容性的原因,最好放在 open 之前

// readystatechange 事件监听 readyState 这个状态的变化
// 它的值从 0 ~ 4,一共 5 个状态
// 0:未初始化。尚未调用 open()
// 1:启动。已经调用 open(),但尚未调用 send()
// 2:发送。已经调用 send(),但尚未接收到响应
// 3:接收。已经接收到部分响应数据
// 4:完成。已经接收到全部响应数据,而且已经可以在浏览器中使用了

// 2.3.准备发送请求
xhr.open(
    'HTTP 方法 GET、POST、PUT、DELETE',
    '地址 URL https://www.imooc.com/api/http/search/suggest?words=js ./index.html ./index.xml ./index.txt',
    true
);

// 调用 open 并不会真正发送请求,而只是做好发送请求前的准备工作

// 2.3.发送请求
// 调用 send() 正式发送请求

// send() 的参数是通过请求体携带的数据
xhr.send(null);

// 3.使用 Ajax 完成前后端通信
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
    if (xhr.readyState !== 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
        console.log(typeof xhr.responseText);
    }
};
xhr.open('GET', url, true);
xhr.send(null);

 Get请求

// 1.携带数据
// GET 请求不能通过请求体携带数据,但可以通过请求头携带
const url =
      'https://www.imooc.com/api/http/search/suggest?words=js&username=alex&age=18';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
    }
};

xhr.open('GET', url, true);

xhr.send(null);

// 不会报错,但不会发送数据
xhr.send('sex=male');

// 2.数据编码
// 如果携带的数据是非英文字母的话,比如说汉字,就需要编码之后再发送给后端,不然会造成乱码问题
// 可以使用 encodeURIComponent() 编码
const url = `https://www.imooc.com/api/http/search/suggest?words=${encodeURIComponent(
    '前端'
)}`;
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
    }
};

xhr.open('GET', url, true);

xhr.send(null);

POST请求

// 1.携带数据
// POST 请求主要通过请求体携带数据,同时也可以通过请求头携带
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
    }
};

xhr.open('POST', url, true);

// 如果想发送数据,直接写在 send() 的参数位置,一般是字符串
// xhr.send('username=alex&age=18');

// 不能直接传递对象,需要先将对象转换成字符串的形式
xhr.send({
    username: 'alex',
    age: 18
});
// [object Object]

// 2.数据编码
xhr.send(`username=${encodeURIComponent('张三')}&age=18`);

JSON

初识JSON

// 1.JSON 是什么
// Ajax 发送和接收数据的一种格式
// XML
// username=alex&age=18
// JSON

const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
    }
};

xhr.open('GET', url, true);

xhr.send(null);

// {"code":200,"data":[{"word":"jsp"},{"word":"js"},{"word":"json"},{"word":"js \u5165\u95e8"},{"word":"jstl"}]}
// HTML/XML

// JSON 全称是 JavaScript Object Notation

// 2.为什么需要 JSON
//  JSON 有 3 种形式,每种形式的写法都和 JS 中的数据类型很像,可以很轻松的和 JS 中的数据类型互相转换

// JS->JSON->PHP/Java
// PHP/Java->JSON->JS

JSON的三种形式

                               

// 1.简单值形式
// .json

// JSON 的简单值形式就对应着 JS 中的基础数据类型
// 数字、字符串、布尔值、null

// 注意事项
// ① JSON 中没有 undefined 值
// ② JSON 中的字符串必须使用双引号
// ③ JSON 中是不能注释的

// 2.对象形式
// JSON 的对象形式就对应着 JS 中的对象

// 注意事项
// JSON 中对象的属性名必须用双引号,属性值如果是字符串也必须用双引号
// JSON 中只要涉及到字符串,就必须使用双引号
// 不支持 undefined

// 3.数组形式
// JSON 的数组形式就对应着 JS 中的数组

// [1, "hi", null]

// 注意事项
// 数组中的字符串必须用双引号
// JSON 中只要涉及到字符串,就必须使用双引号
// 不支持 undefined

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
        console.log(typeof xhr.responseText);
    }
};

// xhr.open('GET', './plain.json', true); //"str"
// xhr.open('GET', './obj.json', true);
xhr.open('GET', './arr.json', true);

xhr.send(null);

array.json

[
  {
    "id": 1,
    "username": "张三",
    "comment": "666"
  },
  {
    "id": 2,
    "username": "李四",
    "comment": "999 6翻了"
  }
]

obj.json

{
  "name": "张三",
  "age": 18,
  "hobby": ["足球", "乒乓球"],
  "family": {
    "father": "张老大",
    "mother": "李四"
  }
}

JSON的常用方法

// 1.JSON.parse()
// JSON.parse() 可以将 JSON 格式的字符串解析成 JS 中的对应值
// 一定要是合法的 JSON 字符串,否则会报错
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
        console.log(typeof xhr.responseText);

        console.log(JSON.parse(xhr.responseText));
        console.log(JSON.parse(xhr.responseText).data);
    }
};

xhr.open('GET', './plain.json', true);
xhr.open('GET', './obj.json', true);
xhr.open('GET', './arr.json', true);

xhr.open(
    'GET',
    'https://www.imooc.com/api/http/search/suggest?words=js',
    true
);

xhr.send(null);

// 2.JSON.stringify()
// JSON.stringify() 可以将 JS 的基本数据类型、对象或者数组转换成 JSON 格式的字符串
console.log(
    JSON.stringify({
        username: 'alex',
        age: 18
    })
);

const xhr = new XMLHttpRequest();

xhr.open(
    'POST',
    'https://www.imooc.com/api/http/search/suggest?words=js',
    true
);
xhr.send(
    JSON.stringify({
        username: 'alex',
        age: 18
    })
);

// 3.使用 JSON.parse() 和 JSON.stringify() 封装 localStorage
import { get, set, remove, clear } from './storage.js';

set('username', 'alex');
console.log(get('username'));

set('zs', {
    name: '张三',
    age: 18
});
console.log(get('zs'));

remove('username');
clear();

storge.js

const storage = window.localStorage;

// 设置
const set = (key, value) => {
  // {
  //   username: 'alex'
  // }
  storage.setItem(key, JSON.stringify(value));
};

// 获取
const get = key => {
  // 'alex'
  // {
  //   "username": "alex"
  // }
  return JSON.parse(storage.getItem(key));
};

// 删除
const remove = key => {
  storage.removeItem(key);
};

// 清空
const clear = () => {
  storage.clear();
};

export { set, get, remove, clear };

跨域

初识跨域

// 1.跨域是什么

// 同域,不是跨域
// const url = './index.html';

// http://127.0.0.1:5500

// 不同域,跨域,被浏览器阻止
// const url = 'https://www.imooc.com';
// const xhr = new XMLHttpRequest();

// Access to XMLHttpRequest at 'https://www.imooc.com/' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

// 向一个域发送请求,如果要请求的域和当前域是不同域,就叫跨域
// 不同域之间的请求,就是跨域请求

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
    }
};

xhr.open('GET', url, true);

xhr.send(null);

// 2.什么是不同域,什么是同域
// https(协议)://www.imooc.com(域名):443(端口号)/course/list(路径)

// 协议、域名、端口号,任何一个不一样,就是不同域
// 与路径无关,路径一不一样无所谓

// 不同域
// https://www.imooc.com:443/course/list
// http://www.imooc.com:80/course/list

// http://www.imooc.com:80/course/list
// http://m.imooc.com:80/course/list
// http://imooc.com:80/course/list

// 同域
// http://imooc.com:80
// http://imooc.com:80/course/list

// 3.跨域请求为什么会被阻止
// 阻止跨域请求,其实是浏览器本身的一种安全策略--同源策略

// 其他客户端或者服务器都不存在跨域被阻止的问题

// 4.跨域解决方案
// ① CORS 跨域资源共享
// ② JSONP

// 优先使用 CORS 跨域资源共享,如果浏览器不支持 CORS 的话,再使用 JSONP

CORS跨域资源共享

 // 1.CORS 是什么 由后端负责 前端不用书写
const url = 'https://www.imooc.com';

const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.responseText);
    }
};

xhr.open('GET', url, true);

xhr.send(null);

// Access-Control-Allow-Origin: *
// 表明允许所有的域名来跨域请求它,* 是通配符,没有任何限制

// 只允许指定域名的跨域请求
// Access-Control-Allow-Origin: http://127.0.0.1:5500

// 2.使用 CORS 跨域的过程
// ① 浏览器发送请求
// ② 后端在响应头中添加 Access-Control-Allow-Origin 头信息
// ③ 浏览器接收到响应
// ④ 如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就圆满完成了
// ⑤ 如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问
// ⑥ 如果允许跨域,通信圆满完成
// ⑦ 如果没找到或不包含想要跨域的域名,就丢弃响应结果

// 3.CORS 的兼容性
// IE10 及以上版本的浏览器可以正常使用 CORS

// https://caniuse.com/

JSON跨域资源共享

// 1.JSONP 的原理
// script 标签跨域不会被浏览器阻止
// JSONP 主要就是利用 script 标签,加载跨域文件

// 2.使用 JSONP 实现跨域
// 服务器端准备好 JSONP 接口
// https://www.imooc.com/api/http/jsonp?callback=handleResponse

// 动态加载 JSONP 接口
const script = document.createElement('script');
script.src ='https://www.imooc.com/api/http/jsonp?callback=handleResponse';
document.body.appendChild(script);

// 声明函数
const handleResponse = data => {
    console.log(data);
};

<

//相当于


XHR对象

XHR属性

// 1.responseType 和 response 属性
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        // 文本形式的响应内容
        // responseText 只能在没有设置 responseType 或者 responseType = '' 或 'text' 的时候才能使用
        // console.log('responseText:', xhr.responseText);

        // 可以用来替代 responseText
        console.log('response:', xhr.response);
        // console.log(JSON.parse(xhr.responseText));
    }
};
xhr.open('GET', url, true);

// xhr.responseType = '';
// xhr.responseType = 'text';
xhr.responseType = 'json';

xhr.send(null);
// IE6~9 不支持,IE10 开始支持

// 2.timeout 属性
// 设置请求的超时时间(单位 ms)
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.response);
    }
};

xhr.open('GET', url, true);

xhr.timeout = 10000; //单位ms

xhr.send(null);
// IE6~7 不支持,IE8 开始支持

// 3.withCredentials 属性
// 指定使用 Ajax 发送请求时是否携带 Cookie

// 使用 Ajax 发送请求,默认情况下,同域时,会携带 Cookie;跨域时,不会
// xhr.withCredentials = true;
// 最终能否成功跨域携带 Cookie,还要看服务器同不同意

const url = 'https://www.imooc.com/api/http/search/suggest?words=js'; //跨域
// const url = './index.html';  //同域

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.response);
    }
};

xhr.open('GET', url, true);

xhr.withCredentials = true;

xhr.send(null);

// IE6~9 不支持,IE10 开始支持

XHR的方法

// 1.abort()
// 终止当前请求
// 一般配合 abort 事件一起使用
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.response);
    }
};

xhr.open('GET', url, true);

xhr.send(null);

xhr.abort();

// 2.setRequestHeader()
// 可以设置请求头信息
// xhr.setRequestHeader(头部字段的名称, 头部字段的值);
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
// const url = 'https://www.imooc.com/api/http/json/search/suggest?words=js';

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
    if (xhr.readyState != 4) return;

    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(xhr.response);
    }
};
xhr.open('POST', url, true);

// 请求头中的 Content-Type 字段用来告诉服务器,浏览器发送的数据是什么格式的
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// xhr.setRequestHeader('Content-Type', 'application/json');

// xhr.send(null);
xhr.send('username=alex&age=18');
// xhr.send(
//   JSON.stringify({
//     username: 'alex'
//   })

XHR的事件

// 1.load 事件
// 响应数据可用时触发相当于onreadystatechange
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

// xhr.onload = () => {
//   if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
//     console.log(xhr.response);
//   }
// };
xhr.addEventListener(
    'load',
    () => {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            console.log(xhr.response);
        }
    },
    false
);

xhr.open('GET', url, true);

xhr.send(null);

// IE6~8 不支持 load 事件

// 2.error 事件
// 请求发生错误时触发

const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const url = 'https://www.iimooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.addEventListener(
    'load',
    () => {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            console.log(xhr.response);
        }
    },
    false
);
xhr.addEventListener(
    'error',
    () => {
        console.log('error');
    },
    false
);

xhr.open('GET', url, true);

xhr.send(null);

// IE10 开始支持

// 3.abort 事件
// 调用 abort() 终止请求时触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

const xhr = new XMLHttpRequest();

xhr.addEventListener(
    'load',
    () => {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            console.log(xhr.response);
        }
    },
    false
);
xhr.addEventListener(
    'abort',
    () => {
        console.log('abort');
    },
    false
);

xhr.open('GET', url, true);

xhr.send(null);

xhr.abort();

// IE10 开始支持

// 4.timeout 事件
// 请求超时后触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

const xhr = new XMLHttpRequest();

xhr.addEventListener(
    'load',
    () => {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            console.log(xhr.response);
        }
    },
    false
);
xhr.addEventListener(
    'timeout',
    () => {
        console.log('timeout');
    },
    false
);

xhr.open('GET', url, true);

xhr.timeout = 10;

xhr.send(null);

// IE8 开始支持

Ajax进阶

FormData



  
    
    FormData
  
  
    

封装Ajax



  
    
    封装 Ajax
  
  
    
  


index.js

import Ajax from './ajax.js';

const ajax = (url, options) => {
  return new Ajax(url, options).getXHR();
};

const get = (url, options) => {
  return ajax(url, { ...options, method: 'GET' });
};

const getJSON = (url, options) => {
  return ajax(url, { ...options, method: 'GET', responseType: 'json' });
};

const post = (url, options) => {
  return ajax(url, { ...options, method: 'POST' });
};

export { ajax, get, getJSON, post };

constants.js

// 常量
export const HTTP_GET = 'GET';
export const CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';
export const CONTENT_TYPE_JSON = 'application/json';

utils.js

// 工具函数

// 数据序列化成 urlencoded 格式的字符串
const serialize = param => {
  const results = [];

  for (const [key, value] of Object.entries(param)) {
    results.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
  }

  // ['username=alex', 'age=18'];

  return results.join('&');
};

// 数据序列化成 JSON 格式的字符串
const serializeJSON = param => {
  return JSON.stringify(param);
};

// 给 URL 添加参数
// www.imooc.com?words=js&
const addURLData = (url, data) => {
  if (!data) return '';

  const mark = url.includes('?') ? '&' : '?';

  return `${mark}${data}`;
};

export { serialize, addURLData, serializeJSON };

defaults.js

// 常量
import { HTTP_GET, CONTENT_TYPE_FORM_URLENCODED } from './constants.js';

// 默认参数
const DEFAULTS = {
  method: HTTP_GET,
  // 请求头携带的数据
  params: null,
  // params: {
  //   username: 'alex',
  //   age: 18
  // }
  // username=alex&age=18
  // 请求体携带的数据
  data: null,
  // data: {
  //   username: 'alex',
  //   age: 18
  // }
  // data: FormData 数据

  contentType: CONTENT_TYPE_FORM_URLENCODED,
  responseType: '',
  timeoutTime: 0,
  withCredentials: false,

  // 方法
  success() {},
  httpCodeError() {},
  error() {},
  abort() {},
  timeout() {}
};

export default DEFAULTS;

ajax.js

// 常量
import {
  HTTP_GET,
  CONTENT_TYPE_FORM_URLENCODED,
  CONTENT_TYPE_JSON
} from './constants.js';

// 工具函数
import { serialize, addURLData, serializeJSON } from './utils.js';

// 默认参数
import DEFAULTS from './defaults.js';

// Ajax 类
class Ajax {
  constructor(url, options) {
    this.url = url;
    this.options = Object.assign({}, DEFAULTS, options);

    // 初始化
    this.init();
  }

  // 初始化
  init() {
    const xhr = new XMLHttpRequest();

    this.xhr = xhr;

    // 绑定响应事件处理程序
    this.bindEvents();

    xhr.open(this.options.method, this.url + this.addParam(), true);

    // 设置 responseType
    this.setResponseType();

    // 设置跨域是否携带 cookie
    this.setCookie();

    // 设置超时
    this.setTimeout();

    // 发送请求
    this.sendData();
  }

  // 绑定响应事件处理程序
  bindEvents() {
    const xhr = this.xhr;

    const { success, httpCodeError, error, abort, timeout } = this.options;

    // load
    xhr.addEventListener(
      'load',
      () => {
        if (this.ok()) {
          success(xhr.response, xhr);
        } else {
          httpCodeError(xhr.status, xhr);
        }
      },
      false
    );

    // error
    // 当请求遇到错误时,将触发 error 事件
    xhr.addEventListener(
      'error',
      () => {
        error(xhr);
      },
      false
    );

    // abort
    xhr.addEventListener(
      'abort',
      () => {
        abort(xhr);
      },
      false
    );

    // timeout
    xhr.addEventListener(
      'timeout',
      () => {
        timeout(xhr);
      },
      false
    );
  }

  // 检测响应的 HTTP 状态码是否正常
  ok() {
    const xhr = this.xhr;
    return (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304;
  }

  // 在地址上添加数据
  addParam() {
    const { params } = this.options;

    if (!params) return '';

    return addURLData(this.url, serialize(params));
  }

  // 设置 responseType
  setResponseType() {
    this.xhr.responseType = this.options.responseType;
  }

  // 设置跨域是否携带 cookie
  setCookie() {
    if (this.options.withCredentials) {
      this.xhr.withCredentials = true;
    }
  }

  // 设置超时
  setTimeout() {
    const { timeoutTime } = this.options;

    if (timeoutTime > 0) {
      this.xhr.timeout = timeoutTime;
    }
  }

  // 发送请求
  sendData() {
    const xhr = this.xhr;

    if (!this.isSendData()) {
      return xhr.send(null);
    }

    let resultData = null;
    const { data } = this.options;

    // 发送 FormData 格式的数据
    if (this.isFormData()) {
      resultData = data;
    } else if (this.isFormURLEncodedData()) {
      // 发送 application/x-www-form-urlencoded 格式的数据

      this.setContentType(CONTENT_TYPE_FORM_URLENCODED);
      resultData = serialize(data);
    } else if (this.isJSONData()) {
      // 发送 application/json 格式的数据

      this.setContentType(CONTENT_TYPE_JSON);
      resultData = serializeJSON(data);
    } else {
      // 发送其他格式的数据

      this.setContentType();
      resultData = data;
    }

    xhr.send(resultData);
  }

  // 是否需要使用 send 发送数据
  isSendData() {
    const { data, method } = this.options;

    if (!data) return false;

    if (method.toLowerCase() === HTTP_GET.toLowerCase()) return false;

    return true;
  }

  // 是否发送 FormData 格式的数据
  isFormData() {
    return this.options.data instanceof FormData;
  }

  // 是否发送 application/x-www-form-urlencoded 格式的数据
  isFormURLEncodedData() {
    return this.options.contentType
      .toLowerCase()
      .includes(CONTENT_TYPE_FORM_URLENCODED);
  }

  // 是否发送 application/json 格式的数据
  isJSONData() {
    return this.options.contentType.toLowerCase().includes(CONTENT_TYPE_JSON);
  }

  // 设置 Content-Type
  setContentType(contentType = this.options.contentType) {
    if (!contentType) return;

    this.xhr.setRequestHeader('Content-Type', contentType);
  }

  // 获取 XHR 对象
  getXHR() {
    return this.xhr;
  }
}

export default Ajax;

使用 Proimise 改造封装好的 Ajax



  
    
    使用 Promise 改造封装好的 Ajax
  
  
    
  


index.js

import Ajax from './ajax.js';
// 常量
import {
  ERROR_HTTP_CODE,
  ERROR_REQUEST,
  ERROR_TIMEOUT,
  ERROR_ABORT,
  ERROR_HTTP_CODE_TEXT,
  ERROR_REQUEST_TEXT,
  ERROR_TIMEOUT_TEXT,
  ERROR_ABORT_TEXT
} from './constants.js';

const ajax = (url, options) => {
  // return new Ajax(url, options).getXHR();
  let xhr;
  const p = new Promise((resolve, reject) => {
    xhr = new Ajax(url, {
      ...options,
      ...{
        success(response) {
          resolve(response);
        },
        httpCodeError(status) {
          reject({
            type: ERROR_HTTP_CODE,
            text: `${ERROR_HTTP_CODE_TEXT}: ${status}`
          });
        },
        error() {
          reject({
            type: ERROR_REQUEST,
            text: ERROR_REQUEST_TEXT
          });
        },
        abort() {
          reject({
            type: ERROR_ABORT,
            text: ERROR_ABORT_TEXT
          });
        },
        timeout() {
          reject({
            type: ERROR_TIMEOUT,
            text: ERROR_TIMEOUT_TEXT
          });
        }
      }
    }).getXHR();
  });

  p.xhr = xhr;
  p.ERROR_HTTP_CODE = ERROR_HTTP_CODE;
  p.ERROR_REQUEST = ERROR_REQUEST;
  p.ERROR_TIMEOUT = ERROR_TIMEOUT;
  p.ERROR_ABORT = ERROR_ABORT;

  return p;
};

const get = (url, options) => {
  return ajax(url, { ...options, method: 'GET' });
};

const getJSON = (url, options) => {
  return ajax(url, { ...options, method: 'GET', responseType: 'json' });
};

const post = (url, options) => {
  return ajax(url, { ...options, method: 'POST' });
};

export { ajax, get, getJSON, post };

constants.js

// 常量
export const HTTP_GET = 'GET';
export const CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded';
export const CONTENT_TYPE_JSON = 'application/json';

export const ERROR_HTTP_CODE = 1;
export const ERROR_HTTP_CODE_TEXT = 'HTTP 状态码异常';
export const ERROR_REQUEST = 2;
export const ERROR_REQUEST_TEXT = '请求被阻止';
export const ERROR_TIMEOUT = 3;
export const ERROR_TIMEOUT_TEXT = '请求超时';
export const ERROR_ABORT = 4;
export const ERROR_ABORT_TEXT = '请求终止';

utils.js、defaults.js、ajax.js都一致

Ajax应用

搜索提示



  
    
    搜索提示
  
  
    
    

    二级菜单

    
    
      
        
        二级菜单
        
      
      
        
    
        
      
    
    
    

    多个Ajax请求的并发执行

    
    
      
        
        多个 Ajax 请求的并发执行
        
      
      
        
    加载中

    Ajax扩展

    axios

    
    
      
        
        axios
      
      
        
        
    
        
      
    
    
    

    Fetch

    
    
      
        
        Fetch
      
      
        
      
    
    
    
    
    
      
        
        Fetch
      
      
        
      
    
    
    

    你可能感兴趣的:(http,ajax,网络协议)