IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 必背-7.同源及跨域 -> 正文阅读

[JavaScript知识库]必背-7.同源及跨域

必背-7.同源及跨域

同源与跨域

同源与跨域?

  • 客户端给服务器端发送请求

  • 同源:客户端的http协议、域名、端口号与服务器的三者完全相同

  • 跨域:只要客户端的http协议、域名、端口号其中一个与服务器的这三者不同

真实项目开发中,基本都是跨域的还是同源的?

  • 开发环境:我们在本地开发项目,我们需要调用后台的接口,此时前后端代码基本不在一起,这样的访问是跨域的
  • 生产环境:
    • 如果我们把前后端代码放在同一个服务器下,这样数据的请求是同源的【很少】
    • 一般我们都是分服务器部署[web服务器、数据服务器。。。]这样还是跨域【常用】
    • 我们还会在自己的项目中,调用第三方平台的接口获取数据,这样的还是跨域请求!!

为什么会产生跨域?

  • 服务器资源分离:WEB服务器、数据服务器、
  • 云信息共享:第三方API接口
  • 有助于分离开发:开发跨域、部署同源

解决跨域方法

如何解决跨域请求?

按常用优先级:

  • 第一种:PROXY跨域代理&nginx反向代理【目前最常用
  • 第二种:CORS跨域资源共享
  • 第三种:JSONP

其余方案:postMessage、document.domain+iframe、window.name、location.hash…【不常用了

  • JSONP:

    • ==原理:==利用ajax/fetch存在域的限制(浏览器的安全策略),但是script/link/img...不存在域的限制;
      • 而JSONP的原理就是基于<script src="接口请求地址">向服务器发送请求,绕过域的限制,实现跨域数据访问。
    • ==缺点:==JSONP只能发送GET请求,因为script请求都是get请求,不支持POST请求
    • 具体操作:
      • 第一步:客户端先创建一个"全局函数" func
      • 第二步:基于script的src发送请求,同时把全局函数func传递给服务器:src="http://api.qq.com/?callback=func"
      • 第三步:服务器接受请求,并且获取传递进来的函数,基本callback接收
      • 第四步:准备客户端需要的数据,准备好之后,给客户端返回这样格式的内容:“func(准备好的数据)”
      • 第五步:客户端获取服务器返回的信息,拿到信息之后,发现是吧第一步准备的全局函数执行,把数据作为实参传递给函数,这样我们在全局函数中就可以获取服务器准备的数据。
    • ==特点:==JSONP需要服务器端的支持:服务器端存在对应的callback函数
  • CORS:

    • ==原理:==默认情况下,因为浏览器的安全策略,服务器端不允许非同源客户端请求的;如果想跨域访问,只需要服务器允许即可,所以cors跨域资源共享,就是服务器设置允许访问的源。

    • 具体操作:服务器端设置Access-Control-Allow-Origin:

      • res.header("Access-Control-Allow-Origin","访问源");//res是响应头
        
      res.header("Access-Control-Allow-Credentials",true);//如果设置所有源访问,需要设置这个为true
      
      res.header("Access-Control-Allow-Headers","Content-Type",...);//允许客户端发送的请求头参数
      res.header("Access-Control-Allow-Methods","POST,GET,HEADR...");//允许客户端发送的方法
      
      
      • “*”:允许所有源访问,【不安全,不允许携带资源凭证】

      • “http://127.0.0.1:5500”:只允许某个源

      • 但是无法直接实现允许多个源,

    • 基于CROS给服务器发送请求,会发两次请求,第一次发一个OPTIONS方式的请求,查看是否能够请求成功,成功后再发送第二次获取数据的请求。

  • PROXY跨域代理&nginx反向代理:代理服务器

    • 原理:服务器与服务器之间不存在跨域问题,客户端启动代理服务器(webpack/node):
      • 帮我们预览客户端项目:基于代理服务器可以找到同项目下的页面服务环境,作用如同open-with-liveserver
      • 同时实现数据请求的代理
      • 此时客户端和代理服务器是同源的
      • 服务器和服务器之间不存在跨域的限制
    • 过程:
      • 接收客户端发送的同源请求,紧接着看到真正的服务器上获取真实的数据【服务器和服务器之间不存在跨域问题】,然后把从真实服务器获取的数据返回客户端。
    • ==核心:==在于设置一个代理服务器[开发环境下我们可以基于webpack-dev-server/ndoe]设置,生产环境下我们一般是基于nginx实现代理服务器的
    • 如何实现代理服务器:
      • 可以基于webpack-dev-server创建【通过http-proxy】
    • image-20211123182536173

手撕JSONP

  • 要点:
    • 1、我们最终需要拼装出来一个<script src="http://api.qq.com/?callback=func></script>"这样的子串
    • 2、在内部发送ajax请求,并处理最终的请求。
    • 2、jsonp方法传的参数:
      • url:路径
      • options:配置项
        • params:默认null,对象类型,问号后的参数信息
        • jsonpName:‘callback’,基于哪个字段把全局函数名传递给服务器
/* 
  封装一个jsonp方法「基于promise管理」,执行这个方法可以发送jsonp请求 
    jsonp([url],[options])
      options配置项
      + params:null/对象 问号参数信息
      + jsonpName:'callback' 基于哪个字段把全局函数名传递给服务器
      + ...
*/
(function () {
    //判断是不是普通标准对象
  const isPlainObject = function isPlainObject(obj) {
    let proto, Ctor;
    if (!obj || Object.prototype.toString.call(obj) !== "[object Object]") return false;
    proto = Object.getPrototypeOf(obj);
    if (!proto) return true;
    Ctor = proto.hasOwnProperty('constructor') && proto.constructor;
    return typeof Ctor === "function" && Ctor === Object;
  };
	//拼接字符串方法
  const stringify = function stringify(obj) {
    let keys = Reflect.ownKeys(obj),
      str = ``;
    keys.forEach(key => {
      str += `&${key}=${obj[key]}`;
    });
    return str.substring(1);
  };

  const jsonp = function jsonp(url, options) {
    // 初始化配置项
    if (typeof url !== "string") throw new TypeError('url is not a string~');
    if (!isPlainObject(options)) options = {};
    let { params, jsonpName } = Object.assign(
      {
        params: null,
        jsonpName: 'callback'
      },
      options
    );

    // 返回promise
    return new Promise((resolve, reject) => {
      // 创建全局函数
      let name = `jsonp${+new Date()}`,
        script;
      window[name] = function (data) {
        // 从服务器获取结果
        resolve(data);
        if (script) document.body.removeChild(script);
        Reflect.deleteProperty(window, name);
      };

      // 拼接URL
      if (params && isPlainObject(params)) {
        params = stringify(params);
        url += `${url.includes('?') ? '&' : '?'}${params}`;
      }
      url += `${url.includes('?') ? '&' : '?'}${jsonpName}=${name}`;

      // 基于SCRIPT发送请求
      script = document.createElement('script');
      script.src = url;
      script.async = true;
      script.onerror = () => reject();
      document.body.appendChild(script);
    });
  };

  /* 暴露API */
  if (typeof module === 'object' && typeof module.exports === 'object') module.exports = jsonp;
  if (typeof window !== 'undefined') window.jsonp = jsonp;
})();
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-27 09:48:55  更:2021-11-27 09:50:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 20:40:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码