什么是正向代理和反向代理?

从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。

代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替我们完成某些任务。在技术领域,这个概念也被广泛应用,尤其是在计算机网络通信和程序设计中,代理扮演着相当重要的角色,涉及控制访问、安全保护、能力扩展等复杂而强大的方面。

网络通信中的代理

在计算机网络中,说到代理,经常会谈到正向代理和反向代理的概念。

在详细展开前,我们先使用一个比喻来形象的理解下这两个概念:小明去饭馆吃饭,正向代理就像是小明的朋友帮他去点餐,服务员并不知道最终吃饭的人是小明;而反向代理则像是饭馆的服务员,他们决定把小明的订单送到哪个厨师手里去做。通过这个比喻,我们可以初步感受到正向代理和反向代理在角色和功能上的不同。

搞清楚网络通信中的代理和反向代理,大家只要弄明白两件事:你在公司的电脑是怎么访问到外网的,你部署的网站或者API又是怎么被外网访问到的。

公司电脑上网

首先看公司电脑上网:公司里的电脑一般不会直接连接到互联网,它们通常在一个内网环境中,这既有成本的考虑,也有安全控制的需要。办公电脑一般会先连接到交换机,交换机再连接到路由器,路由器再连接到互联网。

在这些连接中,交换机只是一个小透明,办公电脑可以看到路由器,路由器也可以看到办公电脑,所以交换机不是我们这里所说的代理。

这里真正的代理是路由器,办公电脑访问网络时,请求先到达路由器,路由器做个请求来源的登记,记下这个请求是从哪台电脑发出的,然后再发到互联网上。请求出了路由器,互联网上能够看到的就是这个路由器,而看不到你的办公电脑。数据从远程服务器返回时,也是先到达这个路由器,路由器再根据之前做的请求来源登记,将数据转发到对应的办公电脑上。

这种场景下,路由器就是一个正向代理,代理内网电脑访问互联网。

除了使用路由器这种比较常见的代理方式,其实还有很多方式,比如在浏览器中配置HTTP代理,只允许通过浏览器访问外网。

网站被外网访问

再看网站或者API是怎么被外网访问到的:通常情况下,大家的服务器也是放在内网中的,直接暴露在互联网上会有安全风险,也不利于管理。所以,我们会在服务器和互联网之间设置一个代理服务器,通常是Nginx或者LVS这种负载均衡器。当外网的用户想要访问你的网站或API时,他们的请求首先会发送到这个代理服务器上。

这个代理服务器就是一个反向代理。

反向代理服务器接到请求后,它知道内网中哪台服务器能提供这个服务,于是它就把请求转发给对应的服务器。服务器处理完这个请求后,再把结果发送回反向代理服务器,最后由反向代理服务器返回给外网的用户。

对比

以上就是计算机网络中正向代理和反向代理的基本原理和应用场景,我们再做一个对比,加深印象。

正向代理和反向代理的区别主要体现在它们服务的对象和用途上:

简单来说,正向代理是客户端的代理,帮助客户端访问到无法直接获取的资源;反向代理是服务器的代理,帮助服务器平滑处理来自各方的请求。

程序设计中的代理

在程序设计中,也有一个代理模式,虽然和网络中的正向代理或反向代理的概念不完全一样,但本质上它们都是代理的概念,都是作为中介提供隔离、隐藏、控制访问和功能增强等作用。

Just show me the code! 现在我们用Go来编写一个代理的实例程序,假设我们有一个资源类,我们希望在访问这个资源时,记录访问次数,并在资源不再被引用时自动释放资源。

首先,定义一个资源接口Resource和实现这个接口的资源类MyResource:

package mainimport ("fmt"
)// Resource 接口定义了资源需要实现的方法
type Resource interface {Use()Release()
}// MyResource 是实现了Resource接口的资源类
type MyResource struct{}func (r *MyResource) Use() {fmt.Println("Using MyResource")
}func (r *MyResource) Release() {fmt.Println("Releasing MyResource")
}

然后,定义一个代理的类 ResourceProxy,它包含了对资源的引用和引用计数,同时它也实现了Resource接口。

// ResourceProxy 是代理的结构体,包含资源和引用计数
type ResourceProxy struct {resource ResourcerefCount int
}// NewResourceProxy 是ResourceProxy的构造函数
func NewResourceProxy(resource Resource) *ResourceProxy {return &ResourceProxy{resource: resource, refCount: 1} // 初始引用计数为1
}// Use 方法增加引用计数并使用资源
func (sr *ResourceProxy) Use() {sr.refCount++fmt.Printf("Resource is used %d times\n", sr.refCount)sr.resource.Use()
}// Release 方法减少引用计数,当计数为0时释放资源
func (sr *ResourceProxy) Release() {sr.refCount--if sr.refCount == 0 {sr.resource.Release()} else {fmt.Printf("Resource is still used by %d references\n", sr.refCount)}
}

最后我们使用这个代理:

func main() {resource := &MyResource{}proxyRef := NewResourceProxy(resource)proxyRef.Use() // 使用资源,引用计数增加proxyRef.Release() // 释放一次引用,引用计数减少到0,资源被释放// Output:// Resource is used 1 times// Using MyResource// Releasing MyResource
}

这个简单的例子演示了代理在资源管理中的应用,可以根据实际需要添加更多复杂的逻辑,比如错误处理、同步控制、日志记录等。

在程序设计中,代理模式是一种结构型设计模式,它让我们能提供一个替代品来代表另一个对象,这个替代品控制着对原对象的访问,可以在访问原对象前后进行一些额外处理。

通过上边的示例,我们可以发现代理模式的三个主要角色:

  • 抽象主题(Subject):定义了代理和真实主题的共用接口,这样在任何使用真实主题的地方都可以使用代理。

  • 真实主题(Real Subject):实现了抽象主题的具体类,代表了实际的对象,是最终要使用的对象。

  • 代理(Proxy):包含对真实主题的引用,控制着对真实主题的访问,并可能负责创建和删除它。通常会做一些额外的事情来实现自己的价值。

在代码实际实现时,代理模式其实有多种不同的实现,包括:

  • 远程代理(Remote Proxy):为一个对象在不同的地址空间(通常是不同计算机上的服务)提供局部代表。常见的如RPC、gRPC等,通过本地代理对象,客户端可以像调用本地接口一样访问远程服务,而无需关心网络通信的细节。

  • 虚拟代理(Virtual Proxy):通过它来存放实例化需要很长时间的真实对象。常见的就是懒加载,比如加载一个大文件或者从数据库中读取大量数据,我们不希望在程序启动时就立刻加载,而是希望在真正需要这些数据的时候才去加载它们。

  • 保护代理(Protection Proxy):控制对原始对象的访问。用于对象应该有不同访问权限的时候。

  • 智能引用(Smart Reference):当对象被引用时,提供一些额外的操作,比如计算对象被引用的次数。上边提供的代码示例就是一个智能引用的例子。

这里就不展示更多的代码了,关键是在合适的时机使用恰当的代理模式来解决问题,这需要细细体会。

做个简单的小结,代理模式就像程序中的一个“中间人”,在不需要直接访问某个对象,或者直接访问某个对象不太方便或者不符合需求时,代理模式提供了一个非常灵活的解决方案。

正如本文所探讨的,代理模式在网络通信和程序设计中都扮演着重要的角色。它通过提供一个中间层,增强了系统的安全性、灵活性和可维护性。掌握代理,我们就拥有了在合适的场景下解决问题的一种强大能力。希望本文的讨论能对你有一点用处。

文章转载自:萤火架构

原文链接:https://www.cnblogs.com/bossma/p/18095781

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/568575.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工业级POE交换机的SSH配置步骤

工业级POE交换机的SSH(Secure Shell)配置可以通过以下步骤进行: 1. 连接到POE交换机:使用一个支持SSH协议的终端工具(如PuTTY)连接到POE交换机的管理接口。 2. 登录到POE交换机:输入正确的用户…

nuxt3使用自定义组件

说明:nuxt3只有components文件夹里面的页面会自动注册为组件,但是有些单独的页面也需要组件,但是也不是全局的,所以写在pages里面的页面,需要手动注册为组件使用 1.创建组件 在pages里面创建页面文件夹,在…

CQBF氟塑料磁力泵

引言: 在当今的工业制造和化学处理领域,对高效率、耐用性和安全性的需求日益增长。CQBF氟塑料磁力泵作为这一需求下的创新产品,已经成为许多企业提升工艺水平和确保环境安全的关键工具。本文旨在深入探讨CQBF氟塑料磁力泵的技术特点、应用优势…

qt5-入门-ModelView架构1

参考: Qt model-view 架构_w3cschool https://www.w3cschool.cn/learnroadqt/vtxz1j4y.html QListWidget_w3cschool https://www.w3cschool.cn/learnroadqt/yb2k1j51.html C GUI Programming with Qt 4, Second Edition 本地环境: win10专业版&#x…

SqlServer期末复习(数据库原理及应用)持续更新中

一、SQL语句 1.1 SQL语句知识引入 1.DDL语言(数据定义语言)主要是进行定义/改变表的结构、数据类型、表之间的链接等操作,关键字CREATE、DROP、ALTER CREATE TABLE 表面( 列名1 数据类型, 列名2 数据类型, ) ALTER TABLE 表名&a…

[Android]模拟器登录Google Play失败

问题: 模拟器登录Google Play失败,提示couldnt sign in there was a problem communicating with google servers. try again later. 原因: 原因是模拟器没有连接到互联网,打开模拟器中Google浏览器进行搜索一样不行。 解决&am…

2.9、创建网格(Grid/GridItem)

概述 网格布局是由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。网格布局具有较强的页面均分能力,子组件占比控制能力,是一种重要自适应布局,其使用场景有九宫格图片展示、日历、计算器等。 ArkUI提供了Grid容器组件和子组件GridI…

JDBC基础编程练习

目录​​​​​​​ 第1关:JDBC更新员工密码 任务描述 实验一代码: 第2关:JDBC查询员工信息 任务描述 实验二代码: 第1关:JDBC更新员工密码 任务描述 本关任务:借助JDBC在库名tsgc中完成对数据表emp…

Python:基础语法

一、import与from.....import 有时候我们需要使用一些第三方库或包时,我们就需要通过import或from.....import导入模块。 # 导入库 import sys print("hello,world") 当我们自己写了些函数,在其他py文件,我们也可以通过from.....im…

SQL练习【个人练习】

SQL练习, 去除了过于简单的SQL语句 常用函数的使用concat&substringlike&left切割&正则比较&时间函数(date_format/year/month)时间函数匹配 group by子查询Union 前几天做笔试的时候狠狠拷打了SQL,并不是很难的题目,现在想起…

leetcode 225.用队列实现栈 JAVA

题目 思路 1.一种是用双端队列(Deque),直接就可以调用很多现成的方法,非常方便。 2.另一种是用普通的队列(Queue),要实现栈的先入后出,可以将最后一个元素的前面所有元素出队,然后…

机器学习基础——模型评估与选择(部分)

为了实现对模型指导,实现自主建模,我们会对模型进行选择和评估,主要有以下几个问题: 一、前言:误差与拟合 (一)经验误差 使用上述流程理解,其中 a 为预测错误的个数,m为…