什么是跨域

跨域一个域下的文档或脚本试图去请求另一个域下的资源

广义的跨域包含一下内容

1.资源跳转(链接跳转,重定向跳转,表单提交)
2.资源请求(内部的引用,脚本script,图片img,frame)
3.script内部发起的请求(ajax,dom请求,和js跨域调用

跨域问题出现

只有浏览器端出现,直接用终端请求,是不会出现跨域拦截,是属于浏览器端的安全策略,浏览器将不同源的请求进行了拦截,限制了跨域资源访问

什么是同源

同源策略:same origin policy,如果两个资源(页面)`协议`,`域名`,`端口`都相同,那么就是同源。

即使:两个不同域名指向同一个ip,也算非同源

非同源(跨域)有哪些限制

* cookie,localstorage,indexDB无法读取
* Dom和JS对象无法互通
* Ajax请求不能发送

常见的跨域demo

URL                                      说明                    是否允许通信
http://www.domain.com/a.js
http://www.domain.com/b.js 同一域名,不同文件或路径 允许
http://www.domain.com/lab/c.js http://www.domain.com:8000/a.js
http://www.domain.com/b.js 同一域名,不同端口 不允许 http://www.domain.com/a.js
https://www.domain.com/b.js 同一域名,不同协议 不允许 http://www.domain.com/a.js
http://192.168.4.12/b.js 域名和域名对应相同ip 不允许 http://www.domain.com/a.js
http://x.domain.com/b.js 主域相同,子域不同 不允许
http://domain.com/c.js http://www.domain1.com/a.js
http://www.domain2.com/b.js 不同域名 不允许

前端解决跨域的方法

  • JSONP

    • 原理:由于在一个页面内部js如果要访问另一个非同源域的数据是被浏览器限制的,但是浏览器在解析和加载script标签的时候,是允许一个页面加载多个域的js标签,而js标签其实又是类似一种get请求的方式,只是返回的数据是一个JSON格式的脚本对象。
    • 用法:将get请求封装到script标签中,利用script标签做get请求,最后解析script标签数据
    • 代码:
      var  script = document.createElement('script')
    script.style = 'text/javascript' //将要请求的get地址传到script的src属性,并且添加回调函数
    script.setAttribute('scr','http://www.domain2.com:8080/login?user=admin&callback=handleCallback')
    //将script标签放入文档
    document.head.appendChild(script)
    //执行回调函数
    function handleCallback(res){
    //处理JSON格式数据
    alert(JSON.stringify(res))
    }
    • 由于请求script只能是get方法,所以JSONP这种方式只能解决get请求,post或者其他http方法无法解决
  • 跨域资源共享

    • 原理:

      • cors:cross-origin -resouce sharing跨域资源共享,允许浏览器向跨源服务器发出http请求,需要浏览器和服务器同时支持
      • 浏览器在发出跨域请求时:1。简单请求,直接在头部信息中带上origin信息,标识属于哪个源,服务端配置access-control-allow-origin接受哪些域名跨域访问,可以是*允许所有
      • 如果是非简单请求会在正式请求之前,发送预检请求
    • 简单来说(简单请求):
      • 是一个双端配合,允许打卡跨域资源限制的一种手段
      • 浏览器端:请求头携带origin信息
      • 服务端:配置access-control-allow-origin允许哪些源跨域
    • 代码:
      • 原生:xmlHttpRequest不需要配置请求头,简单请求会自动带上origin属性
        var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
        
            xhr.open('post', 'http://www.domain2.com:8080/login', true);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.send('user=admin'); xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
        }
        };
      • AJAX:有一个属性crossDomain,配置为true之后会让请求头携带orgin跨域额外信息,但是不会自动包含cookie
        $.ajax({
        ...
        xhrFields: {
        withCredentials: true // 前端设置是否带cookie
        },
        crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
        ...
        });
      • VUE中的axios,默认也会把origin放到请求头,不需要额外配置
    • 服务端配置
        /*
      * 导入包:import javax.servlet.http.HttpServletResponse;
      * 接口参数中定义:HttpServletResponse response
      */ // 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
      response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); // 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
      response.setHeader("Access-Control-Allow-Credentials", "true"); // 提示OPTIONS预检时,后端需要设置的两个常用自定义头
      response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
  • 反向代理(NodeJs中间件代理跨域)(Vue代理跨域)(nginx转发代理)

    • 场景:当服务器端无法修改cors,并且client全部换成jsonp方式比较繁琐时,只能通过中间代理服务器,将代理服务器设置为支持CORS或者代理服务器和请求页面同源,使页面可以直接请求代理服务器,在通过代理服务器进行接口代理,代理请求目标接口地址,返回数据

    • 原理:跨域限制仅是浏览器端的安全策略,并不是http协议的固有限制,所以中间服务器在参数和cookie有效的情况下是可以正常的请求目标服务器的,Vue(node+webpack+webpack-dev-server)中配置proxy就是启动一个同源的服务进行接口代理

    • 注意:

      • 1.非vue ,webpack,dev-serve服务,单独启的nginx或者node express服务做反向代理时,一般是跟页面非同源,非同源要访问代理服务器也存在跨域问题,需要配置cors允许跨域访问,配置access-control-allow-header
      • 在webpack-dev-server服务,默认应该是基本与测试环境页面同源,不需要配置请求头允许
    • 代码:

      • webpack-dev-server代理
              module.exports = {
      entry: {},
      module: {},
      ...
      devServer: {
      historyApiFallback: true,
      proxy: [{
      context: '/login',
      target: 'http://www.domain2.com:8080', // 代理跨域目标接口
      changeOrigin: true,
      secure: false, // 当代理某些https服务报错时用
      cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改
      }],
      noInfo: true
      }
      }
      • node express反向代理
      var express = require('express');
      var proxy = require('http-proxy-middleware');
      var app = express(); app.use('/', proxy({
      // 代理跨域目标接口
      target: 'http://www.domain2.com:8080',
      changeOrigin: true, // 修改响应头信息,实现跨域并允许带cookie
      onProxyRes: function(proxyRes, req, res) {
      res.header('Access-Control-Allow-Origin', 'http://www.domain1.com');
      res.header('Access-Control-Allow-Credentials', 'true');
      }, // 修改响应信息中的cookie域名
      cookieDomainRewrite: 'www.domain1.com' // 可以为false,表示不修改
      })); app.listen(3000);
      console.log('Proxy server is listen at port 3000...');
      • nginx转发代理
          #proxy服务器
      server {
      listen 81;
      server_name www.domain1.com; location / {
      proxy_pass http://www.domain2.com:8080; #反向代理
      proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
      index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
      add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
      add_header Access-Control-Allow-Credentials true;
      }
      }
  • 其他js HACK方法

    • 主域相同子域不同场景:docment.domain+iframe

    • 三个页面跨域互传 : location.hash + iframe

    • window.name + iframe

    • H5新增的postMessage(跨窗口消息互通方法)

    • 关于iframe:

      • 其实相当于在当前页面下新开了个子页面。遵循一切页面与页面之间资源访问原则,例如

        • 1.当主页面和iframe页面不同源时,无法互相访问DOM
        • 2.当主域一样,二级域名不同时,document.domain的设置,可以规避同源策略,可以互相访问DOM
    • location.hash:

      • url 末尾#后面跟随的时页面片段标识符,用来表示浏览器渲染哪部分页面信息,但是改变这个值页面不会重新刷新, 并且设置之后,所有页面可以通过document对象访问该窗口的location 信息进行获取,可以实现巧妙跨域
      • 代码:
          //父窗口可以把信息,写入子窗口的片段标识符。
      
          var src = originURL + ‘#’ + data;
      document.getElementById(‘myIFrame’).src = src; //子窗口通过监听hashchange事件得到通知。 window.onhashchange = checkMessage; function checkMessage() {
      var message = window.location.hash;
      // …
      }
    • 同理,window.name也是一种hack方法实现跨域的方式

      • 浏览器窗口有window.name属性。这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。

        父窗口先打开一个子窗口,载入一个不同源的网页,该网页将信息写入window.name属性。

        window.name = data;

        接着,子窗口跳回一个与主窗口同域的网址。

        location = ‘http://parent.url.com/xxx.html’;

        然后,主窗口就可以读取子窗口的window.name了。

        var data = document.getElementById(‘myFrame’).contentWindow.name;

        这种方法的优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。

    • postMessage

      • window.name和location.hash都属于取巧的方式,利用了浏览器页面的非数据属性或者是窗口的固有属性达到跨页面的目的,但是在H5新增了postMessage API,实现跨tab跨窗口的数据通信,允许窗口通信,并且不论是否同源

总结:

常用的,还是代理,还有CORS,或者是JSONP这三种方式,禁止跨域本来就是浏览器的一种安全策略,虽然有一定限制开发者的手脚,但是在一些特殊的网站或者安全性要求比较高的网站,网络安全还是不可忽视的

非常感谢:下面的文章给了我很多的帮助,感谢各位前行者的辛苦付出,可以点击查阅更多信息

前端常见解决跨域问题方案

9种常见的跨域解决方案

前端跨域问题

搞懂:前端跨域问题JS解决跨域问题VUE代理解决跨域问题原理的更多相关文章

  1. 解决vue代理和跨域问题

    一.安装vue-resource插件 安装命令:npm install vue-resource --save  安装完之后在根目录下的package.json检查一下插件的版本 在rourer-in ...

  2. 搞懂前端二进制系列(二):🍈File、FileReader与Base64

    参考资料: JavaScript高级程序设计第四版:File API https://juejin.cn/post/7046313942938812424[前端二进制一次搞清楚] 一.File 类型 ...

  3. 搞懂前端二进制系列(一):🍇 认识Blob对象

    参考资料: https://juejin.cn/post/6844904183661854727 [你不知道的Blob] https://juejin.cn/post/6844904144453517 ...

  4. 【js跨域】js实现跨域访问的几种方式

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  5. 一篇文章让你搞懂如何通过Nginx来解决跨域问题

    Nginx跨域实现   首先大家要搞清楚什么是跨域,为什么会有跨域情况的出现.哪些情况属于跨域? 跨域:由于浏览器的同源策略,即属于不同域的页面之间不能相互访问各自的页面内容 注:同源策略,单说来就是 ...

  6. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  7. 前端总结·基础篇·JS(四)异步请求及跨域方案

    前端总结系列 前端总结·基础篇·CSS(一)布局 前端总结·基础篇·CSS(二)视觉 前端总结·基础篇·CSS(三)补充 前端总结·基础篇·JS(一)原型.原型链.构造函数和字符串(String) 前 ...

  8. 前端跨域问题相关知识详解(原生js和jquery两种方法实现jsonp跨域)

    1.同源策略 同源策略(Same origin policy),它是由Netscape提出的一个著名的安全策略.同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正 ...

  9. VUE前端项目配置代理解决跨域问题

    VUE前端项目配置代理解决跨域问题 问题如下,经常在本地调试接口出现这种问题 解决方式1:Chrome 的扩展插件 以前使用Chrome 的扩展插件,但是有时候还是会出现莫名其妙的问题. 需要梯子才行 ...

随机推荐

  1. 微信自动关闭内置浏览器页面,返回公众号窗口 WeixinJSBridge.call('closeWindow')

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. php中switch与ifelse的效率分析

    1.当被判断的值是常量(固定不变的值)时,switch的运行效率比ifelse的运行效率高: $jiejie=3;   // 变判断的值为常量 switch($jiejie){   case 1:   ...

  3. 十七, Oracle索引约束

    管理索引-原理介绍 索引是用于加速数据存取的数据对象.合理的使用索引可以大大降低i/o次数,从而提高数据访问性能. 单列索引 适当的索引对于大型数据库的性能有不错的提升, 但在创建索引时要小心.选择字 ...

  4. c语言 字符串大小写转换

    https://www.programmingsimplified.com/c/program/c-program-change-case https://docs.microsoft.com/en- ...

  5. 异常:由 spring-session pom 引发

    错误异常 Correct the classpath of your application so that it contains a single, compatible version of o ...

  6. jdbc批量插入数据

    //插入很多书(批量插入用法) public void insertBooks(List<Book> book) {   final List<Book> tempBook=b ...

  7. bootstrap-导航(垂直分组)

    1.运行效果如图所示 2.实现代码如下 <!DOCTYPE html> <html> <head>     <meta charset="utf-8 ...

  8. XmlSerializer .NET 序列化、反序列化

    序列化对象   要序列化对象,首先创建要序列化的对象并设置其公共属性和字段.为此,您必须确定要将XML流存储的传输格式,作为流或文件. 例如,如果XML流必须以永久形式保存,则创建一个FileStre ...

  9. 图论--最短路--dijkstra(含路径输出)模板

    #include<iostream> #include<stack> #include<queue> #include<cstring> #includ ...

  10. RocketMQ搭建全过程

    RocketMQ下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/rocketmq/4.3.0/rocketmq-all-4.3.0-bin-relea ...