代理模式

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-12-15

代理模式(Proxy):由于一个对象不能直接引用另一个对象,所以需要通过代理对象在这两个对象之间起到中介的作用。

在前端应用中,常常使用代理用来解决跨域问题。

站长统计

代理对象有很多,比如img标签通过src属性向其他域下的服务器发送请求,不过这类请求只能是get,并且是单向的。

var Count = (function () {
  var img = new Image();
  return function (params) {
    var str = "http://www.count.com/a.gif?";
    for (var key in params) {
      str += key + "=" + params[key]
    }
    img.src = str;
  }
})();

Count({num: 10})

JSONP

第二个代理对象形式是通过script标签。与image标签一样,通过src属性想其他域下的服务器发送请求,但是script返回的脚本文件是js文件,是可以被执行的,我们通过传递出去指定的callback函数名,使得返回的脚本,来执行该callback并传入相关的数据。

<script src="http://localhost/test/josnp.php?callback=jsonpCb"></script>
<script>
  window.jsonpCb = function (data) {
    console.log(data);
  }
</script>

对应的服务器则只需要根据参数返回一段能被执行的脚本即可。取得对应的callback函数名,然后返回 jsonpCb("服务器传给你的数据") 这样一段脚本文件即可,这段脚本文件被加载执行,对应的回调函数就会被调用。

代理模板

关于代理模板的解决思路是这样的,既然不同域之间相互调用对方的页面是有限制的,那么自己域中的两个页面相互之间的调用是可以的,即代理页面B访问被代理页面A是可以的,要实现这种方式我们只需要在被访问的域中,请求返回的Header重定向到代理页面,并在代理页面访问被代理页面即可。

即X域中的A页面发送请求到Y域,Y域接收到请求后处理重新向到X域中B页面,并通过URL携带数据,X域中的B页面被访问时会解析URL获取数据然后调用A页面的回调函数。

A页面 => http://localhost:8000/page/index.html

<script>
  function cb(data) {
    console.log("成功接受数据", data)
  }
</script>

<!-- action: 规定当提交表单时向何处发送表单数据。 -->
<!-- target: 规定在何处打开 action URL。 (framename/_blank/_self/_parent/_top) -->
<form action="http://localhost:3000/test/proxy" method="post" target="proxyIframe" >
  <input type="text" name="callback" value="cb">
  <input type="text" name="proxy" value="http://localhost:8000/page/proxy.html">
  <input type="submit" value="提交">
</form> 
<iframe name="proxyIframe" id="proxyIframe"></iframe>

B页面 => http://localhost:8000/page/proxy.html

<script>
  window.onload = function () {
    if (top == self ) return;
    var arr = location.search.substr(1).split('&');
    var fn, args = {};
    for (var i = 0, len = arr.length; i < len; i++) {
      const [key, value] = arr[i].split('=');
      if (key === 'callback') {
        fn = value;
      } else  {
        args[key] = value;
      }
    }
    try {
      eval(`top.${fn}(${JSON.stringify(args)})`)
    } catch (error) {
      // handle error
    }
  }
</script>

Y域对应的服务端 => 提供服务的接口http://localhost/test/proxy

后台服务server.js相关代码如下:

// server.js
const Koa = require('koa');
const route = require('koa-route');
const bodyParser = require('koa-bodyparser');
const app = new Koa();
app.use(bodyParser())
 
const redirect_test = ctx => {
  const post_params = ctx.request.body;
  const { proxy, callback } = post_params;
  const url = `${proxy}?callback=${callback}&status=success&data=1`

  ctx.response.redirect(url);
}

app.use(route.post('/test/proxy', redirect_test));
 
 
app.listen(3000, () => {
  console.log('server is running at http://localhost:3000');
})