概念

定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户对象和服务对象之间起到中介的作用。

正向代理

服务对象不知道客户对象是谁,客户对象的请求都通过代理来处理后交给服务对象。客户对象被隐藏


反向代理

客户对象不知道服务对象是谁,客户端只发请求给代理,代理分发任务。服务对象被隐藏

实例

访问 http://www.google.com

用浏览器访问http://www.google.com,被拒绝,于是我们在国外搭建一台代理服务器,让代理去帮忙请求,代理把请求的结果再返回给我们

静态代理

在运行前代理就知道目标对象是哪一个

动态代理

在运行时才知道目标对象是哪一个

虚拟代理

如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建

服务端代理服务

网关代理可能单独放在一台服务器或多台服务器上,也可能只在服务器做了个配置(qiong),这些代理服务也可以在其它服务器上实现。
一系列web容器(iis,ngnix,tomcat,jetty…),node… 都封装了或多或少或强或弱 对于一些 基本网关上的服务

封装request

封装response

负载均衡

负载均衡简单来说 就是对 http,https,tcp,udp等请求,通过自己的算法找出一台合适的服务器,将请求转发到这台服务器上。
方案: F5/DNS/LVS/Nginx 等,ngnix 有擅长调度,稳定,等优点,是目前企业应用最广泛的代理代理工具。

代理服务器缓存

在客户端和服务器之间的缓存服务,可以在网关用ngnix配置,也可以在服务端web容器中去做
例如:
在网关记录用户(或某个用户)某个资源的访问率,访问率合格则将其资源缓存,如果不合格则将其清除
或者医生问诊下的病人信息(放在浏览器有安全问题),鉴权通过后将该医生的病人信息返回到客户端

压缩

gzip
Accept-Encoding表示Http响应是否进行压缩,一般的浏览器在访问网页时,是默认在请求头中加入
Accept-Encoding: gzip, deflate ,表示这个请求的内容希望被压缩,压缩的目的是为了减少网络流量,
但是这个只是协议,只能是要求而不是强制的,如果服务器不支持压缩或者没有开启压缩,则不能起到作用,
如果服务器也是支持压缩或者开启压缩,则会在响应头中加入Content-Encoding: gzip 头部
图片如jpg、png文件本身就会有压缩,所以就算开启gzip后,压缩前和压缩后大小没有多大区别,所以开启了反而会白白的浪费资源。

node(compression)

  1. var compression = require('compression')
  2. var app = express();
  3. //尽量在其他中间件前使用compression
  4. app.use(compression());

node(koa)

  1. const compress = require('koa-compress');
  2. const app = module.exports = new Koa();
  3. app.use(compress());

ngnix

一般把它定义在nginx.conf的http{…..}之间

  1. http {
  2. .......
  3. gzip on;
  4. gzip_min_length 1k;
  5. gzip_buffers 4 16k;
  6. gzip_http_version 1.1;
  7. gzip_comp_level 9;
  8. gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php application/javascript application/json;
  9. gzip_disable "MSIE [1-6]\.";
  10. gzip_vary on;
  11. }

减速上传

客户端上传较大文件到服务端,上传文件会占用较大的带宽,如果不作限制,上传文件长时间占用带宽会导致其他请求无法请求 ngnix可配置

解决跨域

以ngnix为例看跨域的解决配置

ngnix配置地址代理

  1. server{
  2. listen 5000;
  3. server_name serverHostName;
  4. location = / {
  5. proxy_pass http://serverHostName:5501/xx.html;
  6. }
  7. location /test {
  8. proxy_pass http://serverHostName:3000/test;
  9. }
  10. }

客户端js

  1. http.get('http://serverHostName:5000/test').then(response=>{})

客户端发送请求http://serverHostName:5000/test 到代理服务器,代理服务器开了个 5000端口监听请求,代理配置了 / 和 /test 两种路径,最终发送请求到 http://serverHostName:3000/test 拿到结果 返回给 浏览器

ngnix配置响应头response-hesder

  1. server{
  2. listen 5000;
  3. server_name localhost;
  4. location = / {
  5. proxy_pass http://localhost:3000/;
  6. }
  7. location /test {
  8. # 指定允许跨域的方法,*代表所有
  9. add_header Access-Control-Allow-Methods *;
  10. # 预检命令的缓存,如果不缓存每次会发送两次请求
  11. add_header Access-Control-Max-Age 3600;
  12. # cookie请求需要加上这个字段,并设置为true
  13. add_header Access-Control-Allow-Credentials true;
  14. # 表示允许这个域跨域调用(客户端发送请求的域名和端口)
  15. # $http_origin动态获取请求客户端请求的域 不用*的原因是带cookie的请求不支持*号
  16. add_header Access-Control-Allow-Origin $http_origin;
  17. # 表示请求头的字段 动态获取
  18. add_header Access-Control-Allow-Headers
  19. $http_access_control_request_headers;
  20. # OPTIONS预检命令,预检命令通过时才发送请求
  21. # 检查请求的类型是不是预检命令
  22. if ($request_method = OPTIONS){
  23. return 204;
  24. }
  25. }
  26. }

客户端js

  1. http.get('http://serverHostName:5000/test').then(response=>{})

客户端发送请求http://serverHostName:5000/test 到代理服务器,代理服务器开了个 5000端口监听请求,拦截/test 的请求,对浏览器的预检 option请求做校验,校验通过给浏览器返回 204,在response header中设置跨域参数,告诉浏览器通过了跨域的校验。
跟在服务端用java,node…加的response-header一样,好处就是对于一类请求可能不在一个服务里,在网关统一配置,减少服务端的重复工作。

加密和ssl加密

安全防火墙

外网发布

前端开发代理模式

图片占位图

页面加载完成前的loading,骨架屏,懒加载占位图,都是在真正的资源被请求完成前被创建的虚拟资源,是虚拟代理的一种

dev-server

在开发环境(我们为了模拟浏览器从服务器获取资源进行渲染,但开发阶段服务器并未部署前端代码,我们在本地开了个服务模拟服务端,浏览器访问这个模拟的本地服务端,进行开发,前端通常叫dev-server)
dev-server.sketch
webpack 中的webpack-dev-server,vue-cli 以及相关打包工具 和 脚手架等,基本都能起个dev-server,webpack和vue-cli 中提供了 关于 proxy 的配置
webpack:

  1. devServer: {
  2. contentBase: path.resolve(__dirname, '..'),
  3. publicPath: path.resolve(__dirname, '..', '/', router.path),
  4. compress: true,
  5. port: 9001
  6. proxy: {
  7. '/fuwu1': {
  8. target: `http://${env}.fuwu1.com/`,
  9. pathRewrite: { '^/fuwu1': '' },
  10. changeOrigin: true,
  11. onProxyReq: req => {
  12. req.setHeader('x-weimai-token', token);
  13. },
  14. onProxyRes: res => {
  15. }
  16. },
  17. '/fuwu2': {
  18. target: `http://${env}.fuwu2.com/`,
  19. pathRewrite: { '^/fuwu2': '' },
  20. changeOrigin: true
  21. }
  22. },
  23. },

在浏览器 请求 /fuwu1/接口1 会被 本地服务转发 到 http://${env}.fuwu1.com/接口1
如果不设置pathRewrite 就是 http://${env}.fuwu1.com/fuwu1/接口1
在这里也可以对请求响应的上下文进行更改 和 处理
浏览器的 请求永远都是到本地服务器 http://localhost:9001/fuwu1/接口1
vue-cli的配置同理
他们都是集成了 http-proxy-middleware ,他封装在 http-proxy
源码 https://github.com/http-party/node-http-proxy

事件委托

例子,一个页面有很多button, 需要绑定很多click事件
利用事件的冒泡,将所有事件委托给他们的父元素,父元素的监听器不关系是哪个子元素被触发,只把结果返回给回调函数

es6-Proxy

引用计数(垃圾回收算法)

当为一个变量分配了内存空间(new * )顺便在对象头中分配了一块内存来保存该对象的引用次数,这块内存可以叫做这块内存的代理器,垃圾回收机制不必关心这个对象有没有在被引用**,只需要关心代理器(计数器)的计数是否为0。