网络模块封装—josnp 和 axios


跨域

  • 1、通过jsonp跨域script 标签的src属性可以跨域引用文件,jsonp是请求之后后台包装好一段json,并且把数据放在一个callback函数,返回一个js文件,动态引入这个文件,下载完成js之后,会去调用这个callback,通过这样访问数据。
    在浏览器端定义一个回调函数,并将函数名通过src传至服务器端;
    服务器端将数据包装成为一段js数据,并返回js函数格式的js文件,接着拿到这个js文件之后函数自动调用,拿到后端返回的数据。

  • 2、跨域资源共享(CORS)普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
    需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。
    如果想实现当前页cookie的写入,在nginx反向代理中设置proxy_cookie_domain 和 NodeJs中间件代理中cookieDomainRewrite参数的设置。
    目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案

  • 3、 nginx代理跨域跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。
    实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

  • 4、WebSocket协议跨域WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,允许服务器端主动向浏览器端发送消息除了上面的4中外,还有几种可以参考的方式,具体使用可以根据实际情况来进行选型:

  • 5、 document.domain + iframe跨域

  • 6、 location.hash + iframe

  • 7、 window.name + iframe跨域

  • 8、 postMessage跨域


JSONP

一种常见的网络请求方式就是JSONP
使用JSONP最主要的原因往往是为了解决跨域访问的问题.

JSONP的核心在于通过

JSONP的缺点
只能发送get请求,因为script只能发送get请求
需要后台配合,此种情况需要前后台配合,将返回结果返回callback(result)的形式
在这里插入图片描述在这里插入图片描述


Ajax、fetch、axios

  • ajax:
    【优点:局部更新;原生支持】
    【缺点:可能破坏浏览器后退功能;嵌套回调】
  • jqueryAjax:
    【在原生的ajax的基础上进行了封装;支持jsonp】
  • fetch:
    【优点:解决回调地狱】
    【缺点:API 偏底层,需要封装;默认不带Cookie,需要手动添加; 浏览器支持情况不是很友好,需要第三方的ployfill】
  • axios:【几乎完美】
    支持浏览器和node.js
    支持promise
    能拦截请求和响应
    能转换请求和响应数据
    能取消请求
    自动转换JSON数据
    浏览器端支持防止CSRF(跨站请求伪造)

Ajax、fetch、axios的区别与优缺点

参考博客

原生ajax

    //创建异步对象  
    var xhr = new XMLHttpRequest();
    //设置请求基本信息,并加上请求头
    xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xhr.open('post', 'test.php' );
    //发送请求
    xhr.send('name=Lan&age=18');
    xhr.onreadystatechange = function () {
        // 这步为判断服务器是否正确响应
      if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
      } 
    };

jqueryAjax

var loginBtn =  document.getElementsByTagName("button")[0];
loginBtn.onclick = function(){
    ajax({
        type:"post",
        url:"test.php",
        data:"name=lan&pwd=123456",
        success:function(data){  console.log(data);  }
    });
}

fetch

fetch('http://www.mozotech.cn/bangbang/index/user/login', {
    method: 'post',
    headers: {  'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams([ ["username", "Lan"],["password", "123456"] ]).toString()
})
.then(res => { console.log(res);  return res.text();})
.then(data => { console.log(data);})

axios

axios({
    method: 'post',
    url: '/abc/login',
    data: { userName: 'Lan',    password: '123' }
})
.then(function (response) { console.log(response);})
.catch(function (error) { console.log(error);});

//  1.axios的基本使用-----------------------------------------------
axios({
  url: 'http://123.207.32.32:8000/home/multidata',
  // method: 'post'
}).then(res => { console.log(res); })

axios({
  url: 'http://123.207.32.32:8000/home/data',
  params: { type: 'pop', page: 1  }     // 专门针对get请求的参数拼接
}).then(res => { console.log(res);  })

//  2.axios发送并发请求---------------------------------------------------
axios.all([axios({ url: 'http://123.207.32.32:8000/home/multidata'}), 
			axios({ url: 'http://123.207.32.32:8000/home/data',
 						 params: { type: 'sell', page: 5 }})])
.then(results => {
  	console.log(results);
  	console.log(results[0]);
 	console.log(results[1]);
})

// 3.使用全局的axios和对应的配置在进行网络请求--------------------------------
// 使用axios.all, 可以放入多个请求的数组.
//axios.all([]) 返回的结果是一个数组,使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2

axios.defaults.baseURL = 'http://123.207.32.32:8000'
axios.defaults.timeout = 5000

axios.all([axios({ url: '/home/multidata'}), 
		axios({ url: '/home/data', params: { type: 'sell', page: 5 }
})]).then(axios.spread((res1, res2) => {
  console.log(res1);
  console.log(res2);
}))

//  4.创建对应的axios的实例
const instance1 = axios.create({
  baseURL: 'http://123.207.32.32:8000',
  timeout: 5000
})

instance1({ url: '/home/multidata'
}).then(res => {  console.log(res); })
instance1({
  url: '/home/data',
  params: { type: 'pop',  page: 1 }
}).then(res => {  console.log(res);  })

const instance2 = axios.create({
  baseURL: 'http://222.111.33.33:8000',
  timeout: 10000,
  // headers: {}
})

同时发送两个请求

function getUserAccount(){
  return axios.get('/user/12345');
}
function getUserPermissions(){
  return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(),getUserPermissions()])
  .then(axios.spread(function(acct,perms){
    //当这两个请求都完成的时候会触发这个函数,两个参数分别代表返回的结果
  }))

常见的配置选项
请求地址		url: '/user',
请求类型		method: 'get',
请根路径		baseURL: 'http://www.mt.com/api',
请求前的数据处理		transformRequest:[function(data){}],
请求后的数据处理		transformResponse: [function(data){}],
自定义的请求头         headers:{'x-Requested-With':'XMLHttpRequest'},
URL查询对象		params:{ id: 12 },

查询对象序列化函数		paramsSerializer: function(params){ }
request body		data: { key: 'aa'},
超时设置s		timeout: 1000,
跨域是否带Token	withCredentials: false,
自定义请求处理	adapter: function(resolve, reject, config){},
身份验证信息		auth: { uname: '', pwd: '12'},
响应的数据格式 json / blob /document /arraybuffer / text / stream
			responseType: 'json',

vue中简单使用axios
<template>
  <h2>{{categories}}</h2>
</template>

<script>
  import axios from 'axios'
  export default {
    name: "HelloWorld",
    data() {  return { categories: '' } },
    created() {
      axios({   url: 'http://123.207.32.32:8000/category'
      }).then(res => {  this.categories = res;  })
    }
  }
</script>

封装到 request模块—回调方式
  • 方式1
//  ./network/request.js  文件
import axios from 'axios'
export function request(config, success, failure) {
  const instance = axios.create({       // 1.创建axios的实例
    baseURL: 'http://123.207.32.32:8000',
    timeout: 5000
  })
  instance(config) 			  // 发送真正的网络请求
    .then(res =>  { success(res);  })
    .catch(err => { failure(err)   })
}

//  main.js 文件
import {request} from "./network/request";
request({  url: '/home/multidata'}, 
	res => {  console.log(res);  }, 
	err => {  console.log(err);
})
  • 方式2
//  ./network/request.js  文件
import axios from 'axios'
export function request(config) {
  const instance = axios.create({
    baseURL: 'http://123.207.32.32:8000',
    timeout: 5000
  })
  instance(config.baseConfig)
    .then(res => {  config.success(res);  })
    .catch(err => { config.failure(err)   })
}

//  main.js 文件
import {request} from "./network/request";
request({
  baseConfig: { },
  success: function (res) {  },
  failure: function (err) {  }
})

封装到 request模块---promise axios封装

//  ./network/request.js  文件

import axios from 'axios'
export function request(config) {
  return new Promise((resolve, reject) => {
    // 1.创建axios的实例对象
    const instance = axios.create({
      baseURL: 'http://123.207.32.32:8000',
      timeout: 5000
    })
    // 过滤器(拦截器)
    instance.interceptors.response.use(res => {  return res.data })
    // 通过实例发送网络请求
    instance(config)
        .then(res => {  resolve(res) })
        .catch(err => {  reject(err) })
  })

//------------  或者  -----------------------------------------------
import axios from 'axios'
export function request(config) {
    const instance = axios.create({
      baseURL: 'http://123.207.32.32:8000',
      timeout: 5000
    })
    return instance(config)   //  instance 本身就返回一个promise  
  }

//  main.js 文件
import {request} from "./network/request";
request({  url: '/home/multidata' })
	.then(res => {  console.log(res);  })
	.catch(err => {  console.log(err); })

将axios异步请求同步化处理

//使用 asyns/await 
async getHistoryData (data) {
 try {
   let res = await axios.get('/api/survey/list/', { params: data})
   this.tableData = res.data.result
   this.totalData = res.data.count
 } catch (err) {  console.log(err) ;	 alert('请求出错!' }
}

axios拦截器的使用

拦截器分为request请求拦截器和response响应拦截器
request请求拦截器:发送请求前统一处理,如:设置请求头headers、应用的版本号、终端类型等。
response响应拦截器:有时候我们要根据响应的状态码来进行下一步操作,例如:由于当前的token过期,接口返回401未授权,那我们就要进行重新登录的操作。

// http request 请求拦截器 : 发送请求之前判断是否存在token,除了登录页,其他页面请求头headers都添加token
axios.interceptors.request.use(config => {
	// 在发送请求之前做些什么
	let pathname = location.pathname;
	if(localStorage.getItem('token')){
		if(pathname != '/' &&  pathname != '/login'){
			config.headers.common['token'] = localStorage.getItem('token');
		}
	}
	return config;
}, error => {	return Promise.reject(error);});

---------------------------------------------------------------------------------
// http response 响应拦截器 : 若返回401,页面跳转到登录页面
axios.interceptors.response.use(response => {
 	return response;
},error => {
 	if (error.response) {
		switch (error.response.status) {			
			case 401:	// 返回401,清除token信息并跳转到登录页面
			localStorage.removeItem('token');
			router.replace({
				path: '/login'				
				// query: {redirect: router.currentRoute.fullPath}	//登录成功后跳入浏览的当前页面
			})
		}		
		return Promise.reject(error.response.data);		// 返回接口返回的错误信息
	}
});

认证Authentication, 授权Authorization, 凭证Credentials

什么是认证(Authentication)

验证当前用户的身份,证明“你是你自己”
用户名密码登录
邮箱发送登录链接
手机号接收验证码

什么是授权(Authorization)

用户授予第三方应用访问该用户某些资源的权限
你在安装手机应用的时候,APP 会询问是否允许授予权限(访问相册、地理位置等权限)
你在访问微信小程序时,当登录时,小程序会询问是否允许授予权限(获取昵称、头像、地区、性别等个人信息)
实现授权的方式有:cookie、session、token、OAuth

什么是凭证(Credentials)

实现认证和授权的前提是需要一种媒介(证书) 来标记访问者的身份


Session

什么是 Session

session 是另一种记录服务器和客户端会话状态的机制
session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储到客户端的cookie 中
SessionID 是连接 Cookie 和 Session 的一道桥梁

session 认证流程:

  • 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session
  • 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器
  • 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
  • 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

Token(令牌)

什么是 Token(令牌)
访问资源接口(API)时所需要的资源凭证

简单 token 的组成: uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)

token 的身份验证流程:
在这里插入图片描述

  • 每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里
  • 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
  • token 完全由应用管理,所以它可以避开同源策略

JWT

JSON Web Token(简称 JWT)是目前最流行的跨域认证解决方案。
是一种认证授权机制。

WT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户
之后,当用户与服务器通信时,客户在请求中发回JSON对象。服务器仅依赖于这个JSON对象来标识用户。为了防止用户篡改数据,服务器将在生成对象时添加签名

服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值