前端跨域方法 手写jsonp

720 阅读2分钟

什么是跨域

  • 浏览器同域策略要求协议、域名、 端口,都一样,只要一种不满足都属于跨域。

跨域有哪一些问题

1、无法获取非同源的cookie、localStorge,sensionStorge, indexedDB,

2、 iframe 页面无法获取

3、 无法发送ajax,fetch 请求,浏览器拒绝,需要服务端支持跨域设置CORS:

  • 服务端设置响应头允许来源:
"Access-Control-Allow-Origin", "*"
  • 服务端设置响应头允许cookie: 服务端 设置Access-Control-Allow-Credentials为true, XMLHttpRequest的withCredentials为true,跨域允许cookie发送
response.setHeader("Access-Control-Allow-Origin", "*");
  • 服务端设置响应头允许methods:
 response.setHeader("Access-Control-Allow-Methods", "*");
  • 服务端设置允许响应头暴露:
 response.setHeader("Access-Control-Expose-Headers", "*");
  • 服务端设置请求的存储时间
response.setHeader("Access-Control-Max-Age", "3600");

js常见的跨域方式:(未完)

1、通过jsonp 跨域

  • JSONP(JSON with Padding)是数据格式 JSON 的一种“使用模式”,可以让网页从别的网域要数据。
  • 根据 XmlHttpRequest 对象受到同源策略的影响,而利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的JSON数据,而这种使用模式就是所谓的 JSONP。
  • 用JSONP抓到的数据并不是JSON,而是任意的JavaScript,用 JavaScript解释器运行而不是用JSON解析器解析。
  • 所有,通过Chrome查看所有JSONP发送的Get请求都是js类型,而非 XHR

缺点

  • 只能使用Get请求
  • 不能注册 success、error 等事件监听函数,不能很容易的确定 JSONP 请求是否失败
  • JSONP 是从其他域中加载代码执行,容易受到xss跨站请求伪造的攻击.

步骤:

  • 1.将传入的data数据转化为url字符串形式
  • 2.处理url中的回调函数
  • 3.创建一个script标签并插入到页面中
  • 4.挂载回调函数

jsonp 代码实现

  function encodeParam(url, obj) {
     // 1.将传入的data数据转化为url字符串形式
     // {id:1,name:'jack'} => id=1&name=jack
     const dataString = url.indexof('?') ? '?' : '&';
     for(let key in data) {
       dataString += `${key}=${(data[key] !== undefinded ? data[key] : '' }`
     }
     return dataString;
  }
  const jsonp = function (url, data, callback) {
  //promise 返回 new Promise((resolve, reject)=>{...callback(data)-->resolve(data)...})
      let dataString = encodeParam(url, data);
      // 处理url 中的回调函数
      const cbfnName = `my_json_cb_${Math.ramdom().toString().repalce('.', '')}`;
      
      dataString += `callback=${cbfnName}`;
      
      // 3.创建一个script标签并插入到页面
      
      const scriptEle = document.createElement('script');
      scriptEle.src = `${url}${dataString}`
      
      // 4、挂载回调函数
      
      window[cbfnName] = function(data) {
        callback(data); 
        // 处理完回调函数的数据之后,删除jsonp的script标
        document.body.removeChild(scriptEle);
      }
      document.body.appendChild(scriptEle);    
  }

服务端代码

let express = require('express');
let app = express();
app.get('/student', function(req, res) {
  let {...callback...} = res.query;
  res.end(`${callback}(data)`)
})