带你了解前端设计模式-🍀代理模式🍀
概述
代理模式
(Proxy Pattern)又称委托模式
,它为目标对象创造了一个代理对象,以控制对目标对象的访问。
代理模式
的关键是,当客户不⽅便直接访问⼀个对象或者不满⾜需要时,提供⼀个替身对象来控制这个对象的访问,客户实际上访问的是替身对象
。
这种结构可以实现在调用目标对象前和调用后进行一些预操作和后操作,从而实现新的功能或者扩展目标的功能。
在前端开发中,代理模式通常用于控制对原始对象的访问,以实现一些额外的逻辑,例如权限验证、缓存、性能优化等。
代理模式在生活中有很多实际应用,以下是一些常见的示例:
代购服务
:假设你想要购买国外的一些商品,但是由于各种原因,无法直接访问国外的在线商店。这时,你可以使用代购服务作为代理,将你的购买请求发送给代购服务,代购服务会帮你完成购买流程并将商品寄送到你的地址。在这个示例中,代购服务充当了你和国外商店之间的代理,为你提供了访问国外商店的间接性。缓存代理
:在浏览器中,当你访问一个网页时,可能存在大量的静态资源需要加载,例如图片、样式表、脚本等。为了提高页面加载速度,浏览器使用缓存代理,将已经获取的资源缓存起来,下次再访问相同的资源时,直接从缓存中获取,而不是重新下载。在这个示例中,缓存代理为用户提供了快速访问资源的能力,减少了网络请求和页面加载时间。身份验证代理
:在很多网站和应用程序中,用户登录时需要进行身份验证。为了保护用户数据的安全,可以使用身份验证代理来拦截用户的登录请求,在用户信息验证通过后,才将请求转发给实际的身份验证服务进行验证。在这个示例中,身份验证代理充当了用户和身份验证服务之间的代理,增加了额外的验证层级,提升了系统的安全性。金融代理
:金融顾问或投资经纪人可以作为客户的代理,帮助他们做出投资决策,代表他们进行买卖交易。旅行代理
:旅行代理是帮助旅客安排旅行事宜的中间人,他们代表旅客与航空公司、酒店、景点等进行交涉和安排,为旅客提供更方便的旅行服务。
这些生活示例展示了代理模式在日常生活中的应用,通过代理模式,我们可以委托他人代替自己进行某些行为或决策,从而节约时间和精力,提高效率和便利性。代理模式在生活中的应用丰富多样,可以帮助人们更好地处理各种事务。
在前端中的应用
代理模式在前端开发中有多种应用场景
,下面列举几个常见的应用:
缓存代理
:使用缓存代理可以缓存计算结果,避免重复的计算或请求。例如,可以使用缓存代理来缓存网络请求的结果,如果下次请求相同的资源,则直接返回缓存的结果而不用再次发送请求。- 拦截器:使用代理对象作为拦截器可以拦截和处理请求、响应或事件。这在实际开发中经常用于添加额外的逻辑、验证、日志记录等操作。例如,可以使用拦截器拦截网络请求,在发送请求前添加统一的请求头或记录日志。
虚拟代理
:使用虚拟代理可以延迟加载资源或延迟执行昂贵的操作,从而提高页面的响应速度和用户体验。例如,在图片加载时可以使用虚拟代理,只有当图片需要显示时才实际加载图片数据。保护代理
:保护代理可以用来限制对敏感操作或数据的访问权限。在前端开发中,可以使用保护代理来控制用户对特定功能的访问权限,例如需要登录才能进行操作的功能或需要特定权限才能查看的数据。正向代理
: 一般的访问流程是客户端直接向目标服务器发送请求并获取内容,使用正向代理后,客户端改为向代理服务器发送请求,并指定目标服务器(原始服务器),然后由代理服务器和原始服务器通信,转交请求并获得的内容,再返回给客户端。正向代理隐藏了真实的客户端,为客户端收发请求,使真实客户端对服务器不可见;反向代理
: 与一般访问流程相比,使用反向代理后,直接收到请求的服务器是代理服务器,然后将请求转发给内部网络上真正进行处理的服务器,得到的结果返回给客户端。反向代理隐藏了真实的服务器,为服务器收发请求,使真实服务器对客户端不可见。- .....
缓存代理
缓存代理可以为⼀些开销⼤的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前⼀致,则可以直接返回前⾯存储的运算结果 。
在前端开发中,使用代理模式实现缓存代理可以帮助减少重复的计算或请求,提高性能并降低资源消耗。下面是一个简单的 JavaScript 代码示例,用于模拟前端缓存代理:
// 目标对象:计算器函数
class Calculator {
multiply(a, b) {
console.log(`Calculating ${a} * ${b}`);
return a * b;
}
}
// 代理对象:缓存代理
class CachingProxy {
constructor() {
this.calculator = new Calculator();
this.cache = {};
}
multiply(a, b) {
const key = `${a}*${b}`;
if (this.cache[key] === undefined) {
this.cache[key] = this.calculator.multiply(a, b);
}
return this.cache[key];
}
}
// 使用缓存代理进行乘法计算
const proxy = new CachingProxy();
console.log(proxy.multiply(2, 3)); // 第一次计算
console.log(proxy.multiply(2, 3)); // 从缓存中获取结果
console.log(proxy.multiply(4, 5)); // 新的乘法计算
console.log(proxy.multiply(4, 5)); // 从缓存中获取结果
在这个示例中,Calculator
表示目标对象,即计算器函数,它具有 multiply
方法用于进行乘法计算。CachingProxy
表示代理对象,它包含一个对 Calculator
的实例,并且也具有 multiply
方法。在 CachingProxy
的 multiply
方法中,我们首先检查缓存中是否存在要计算的结果,如果存在则直接从缓存中获取,否则调用 Calculator
进行计算,并将结果存入缓存。
拦截器
在前端开发中,代理模式还可以用于创建拦截器,用于拦截和处理请求、响应或事件。这在实际开发中经常用于添加额外的逻辑、验证、日志记录等操作。
下面是一个简单的 JavaScript 代码示例,用于模拟前端拦截器:
// 请求拦截器
const requestInterceptor = async (config) => {
console.log('Request Interceptor:', config);
// 添加统一请求头
config.headers = {
'Content-Type': 'application/json'
};
return config;
};
// 响应拦截器
const responseInterceptor = async (response) => {
console.log('Response Interceptor:', response);
// 处理错误逻辑
if (response.status >= 400) {
console.error('Request failed:', response.statusText);
}
return response;
};
// 模拟发送请求的函数
const sendRequest = async (url, config) => {
console.log('Sending request:', url);
// 进行请求拦截
const updatedConfig = await requestInterceptor(config);
// 发送请求
const response = await fetch(url, updatedConfig);
// 进行响应拦截
const updatedResponse = await responseInterceptor(response);
return updatedResponse;
};
// 发送请求
sendRequest('https://jsonplaceholder.typicode.com/posts/1', {
method: 'GET'
});
在上面的示例中,requestInterceptor
函数表示请求拦截器,用于添加统一的请求头;responseInterceptor
函数表示响应拦截器,用于处理错误逻辑。sendRequest
函数模拟发送请求的过程,其中通过请求拦截器对请求进行处理,通过响应拦截器对响应进行处理。
反向代理
在前端开发中,虽然反向代理通常是在服务器端设置和配置的,但是前端开发人员也会涉及到与反向代理相关的工作。特别是在开发过程中,前端开发人员可能需要使用反向代理来解决跨域访问、本地开发环境代理等问题。
- 跨域访问:在前端开发中,由于浏览器的同源策略限制,导致跨域请求受到限制。为了解决跨域问题,可以通过配置反向代理来实现跨域访问。前端开发人员可以配置代理将浏览器的请求转发给目标服务器,并在代理服务器上进行必要的处理,如添加响应头、修改请求路径等,从而实现跨域请求。
- 本地开发环境代理:在前端开发过程中,通常会使用本地开发环境进行调试和开发。当前端项目需要与后端接口进行交互时,可能需要通过反向代理将接口请求代理到后端服务器,以便在本地开发环境中进行调试和开发。前端开发人员可以配置反向代理将接口请求转发到后端服务器,而不需要修改前端代码中的接口地址。
在前端开发中,通常可以使用webpack-dev-server等工具来配置代理实现反向代理。以下是一个简单的webpack配置示例,演示如何在前端开发中使用代理实现反向代理:
const path = require('path');
const webpack = require('webpack');
module.exports = {
// ...其他webpack配置
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
proxy: {
'/api': {
target: 'http://backend-server.com',
pathRewrite: {'^/api' : ''},
changeOrigin: true
}
}
}
};
在这个示例中,我们使用了webpack-dev-server提供的proxy配置选项,将所有以/api开头的请求转发到backend-server.com。具体说明如下:
target
指定了目标后端服务器的地址。pathRewrite
用于重写路径,这里将请求路径中的/api前缀去掉。changeOrigin
用于控制请求头中的host字段,如果设置为true,那么请求头中的host字段会被设置为目标服务器的地址。
通过这样的配置,前端开发人员可以在本地开发环境中发起对/api
路径下接口的请求,而这些请求会被代理服务器转发到实际的后端服务器上。这样就实现了反向代理的效果,同时避免了跨域问题,并且能够在本地开发环境中方便地调试和开发。
优缺点
前端代理模式作为一种设计模式,在前端开发中具有一些优点和缺点,下面对其进行简要总结:
优点:
控制访问
:代理对象可以控制访问目标对象,从而可以在访问目标对象之前或之后执行一些额外的逻辑,例如权限校验、缓存数据等。隐藏复杂性
:代理模式可以封装目标对象的复杂性,使客户端对目标对象的具体实现细节进行解耦,增强了代码的可维护性和可读性。增强安全性
:通过代理对象可以对访问请求进行安全过滤和验证,确保数据的安全性和完整性。性能优化
:代理模式可以实现一些性能优化策略,例如延迟加载、数据缓存等,从而提升系统的性能和响应速度。
缺点:
增加复杂性
:引入代理对象会增加代码的复杂性,需要额外的开发和维护工作,可能会导致系统变得难以理解和维护。性能损失
:在使用代理模式时,会增加一定的开销,例如代理对象的创建、额外逻辑的执行等,可能会对系统的性能产生一定影响。可能引入新问题
:设计和实现代理模式时需要考虑到代理对象与目标对象之间的交互逻辑,如果设计不合理或实现有误,可能会引入新的问题和 bug。
总的来说,前端代理模式具有一些优点,如控制访问、隐蔽复杂性和安全性增强等,但也存在一些缺点,如增加复杂性、性能损失和可能引入新问题。在实际开发中,需要根据具体的需求和场景来选择是否使用代理模式,以达到更好的设计和实现效果。
参考文献
转载自:https://juejin.cn/post/7373609752237981759