精华内容
下载资源
问答
  • 跨域请求

    2017-02-06 16:35:17
    最近闲来无事做个个人网站耍,部署到服务器的时候发现有个字体文件老是下载不下来,浏览器老是报不允许跨域请求。什么是跨域以及产生原因跨域是指a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同...

    背景

    最近闲来无事做个个人网站耍,部署到服务器的时候发现有个字体文件老是下载不下来,浏览器老是报不允许跨域请求。

    什么是跨域以及产生原因

    跨域是指a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,或是a页面为ip地址,b页面为域名地址,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。
      跨域情况如下:
      

    url 说明 是否跨域
    http://www.cnblogs.com/a.js
    http://www.a.com/b.js
    不同域名
    http://www.a.com/lab/a.js
    http://www.a.com/script/b.js
    同一域名,不同文件夹
    http://www.a.com:8000/a.js
    http://www.a.com/b.js
    同一域名,不同端口
    http://www.a.com/a.js
    https://www.a.com/b.js
    同一域名,不同协议
    http://www.a.com/a.js
    http://70.32.92.74/b.js
    域名和域名对应IP
    http://www.a.com/a.js
    http://script.a.com/b.js
    主域相同,子域不同 是(cookie不可访问)
    http://www.a.com/a.js
    http://a.com/b.js
    同一域名,不同二级域名(同上)

    跨域的常见解决方法

    目前来讲没有不依靠服务器端来跨域请求资源的技术

    1. jsonp 需要目标服务器配合一个callback函数。
    2. window.name+iframe 需要目标服务器响应window.name。
    3. window.location.hash+iframe 同样需要目标服务器作处理。
    4. html5的 postMessage+ifrme 这个也是需要目标服务器或者说是目标页面写一个postMessage,主要侧重于前端通讯。
    5. CORS 需要服务器设置header :Access-Control-Allow-Origin。
    6. nginx反向代理 这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求。

    我的情况

    写了一个博客系统玩,自己的服务器,采用Nginx代理转发请求到tomcat。
    部署完项目后浏览器里面访问,发现有几个图标出不来,经检测是字体文件被浏览器认为是跨越请求,没有被加载。该字体文件不是由页面直接引用,而是通过一个css文件加载的,该css加载无问题。字体文件和css文件都在工程目录下,理应不会出现跨域请求的情况。
    在火狐浏览器里面打开网络请求查看器,点开请求结果为0字节的字体请求连接,结果如下:
    跨域请求
    跨域请求

    这个字体文件是通过字体css依赖加载的,并不是通过页面直接引用。
    发现请求头Host是 itclj.com 而Origin是http://www.itclj.com
    响应Server是由Nginx报出来的,进过定位,应该是Nginx认为,源主机是www.itclj.com,目标主机是itclj.com不来自同一个域,所以被认为是非法请求。

    Nginx配置如下:
    nginx配置

    在浏览器里面请求www.itclj.com的时候Nginx会自动解析为服务名itclj.com,代理转发后请求变为了http://itclj.com,通过代理的文件来发起请求的主机就变成了itclj.com,浏览器里面实际的主机是www.itclj.com所以,所以被Nginx认为是跨域请求了。
    修改Nginx为如下配置即可。

    Nginx配置

    修改配置重启Nginx即解决问题。

    展开全文
  • 八种方式实现跨域请求

    万次阅读 多人点赞 2017-06-11 22:52:54
    前端开发中我们经常会遇到跨域请求的情况,处理跨域请求方式很多,特整理如下: 浏览器的同源策略​ 提到跨域不能不先说一下”同源策略”。 ​ 何为同源?只有当协议、端口、和域名都相同的页面,则两个页面具有...

    前端开发中我们经常会遇到跨域请求的情况,处理跨域请求方式很多,特整理如下:

    浏览器的同源策略

    首选,跨域是由于浏览器端的同源策略限制所得来。

    同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

    那么,何为同源呢?只有当协议端口域名都相同的页面,则两个页面具有相同的。只要网站的协议protocol、 主机host、 端口号port 这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用,会受到同源策略的限制。

    浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用(通常指使用 XMLHttpRequest 请求)。

    跨域请求方式

    解决跨域问题,最简单的莫过于通过 Nginx 反向代理 进行实现,但是其需要在服务器层面修改,且有可能请求的资源并不再我们控制范围内(第三方),所以该方式不能作为通用的解决方案,下面阐述了经常用到几种跨域方式:

    方式一:图片ping或script标签跨域

    图片ping 常用于跟踪用户点击页面或动态广告曝光次数。
    script标签 可以得到从其他来源数据,这也是 JSONP 依赖的根据。

    <img src="https://domain.com/pn">
    

    缺点

    • 只能发送Get请求 ,无法访问服务器的响应文本(单向请求)

    方式二:JSONP跨域

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

    缺点:

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

    方式三:CORS

    Cross-Origin Resource Sharing(CORS)跨域资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,确保安全的跨域数据传输。现代浏览器使用CORS在API容器如XMLHttpRequest来减少HTTP请求的风险来源。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。服务器一般需要增加如下响应头的一种或几种:

    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
    Access-Control-Max-Age: 86400
    

    跨域请求默认不会携带Cookie信息,如果需要携带,请配置下述参数:

    Access-Control-Allow-Credentials: true
    # Ajax设置
    withCredentials: true
    

    方式四:window.name+iframe

    window.name通过在iframe(一般动态创建i)中加载跨域HTML文件来起作用。然后,HTML文件将传递给请求者的字符串内容赋值给window.name。然后,请求者可以检索window.name值作为响应。

    • iframe 标签的跨域能力;
    • window.name 属性值在文档刷新后依旧存在的能力(且最大允许2M左右)。

    每个 iframe 都有包裹它的 window,而这个 window 是 top window 的子窗口。contentWindow属性返回<iframe>元素的Window对象。你可以使用这个Window对象来访问iframe的文档及其内部DOM。

    下述用端口:10000表示 — domainA;10001表示 — domainB

    <!-- localhost:10000 -->
    <script>
      var iframe = document.createElement('iframe');
      iframe.style.display = 'none'; // 隐藏
    
      var state = 0; // 防止页面无限刷新
      iframe.onload = function() {
          if(state === 1) {
              console.log(JSON.parse(iframe.contentWindow.name));
              // 清除创建的iframe
              iframe.contentWindow.document.write('');
              iframe.contentWindow.close();
              document.body.removeChild(iframe);
          } else if(state === 0) {
              state = 1;
              // 加载完成,指向当前域,防止错误(proxy.html为空白页面)
              // Blocked a frame with origin "http://localhost:10000" from accessing a cross-origin frame.
              iframe.contentWindow.location = 'http://localhost:10000/proxy.html';
          }
      };
    
      iframe.src = 'http://localhost:10001';
      document.body.appendChild(iframe);
    </script>
    
    <!-- localhost:10001 -->
    <!DOCTYPE html>
    ...
    <script>
      window.name = JSON.stringify({a: 1, b: 2});
    </script>
    </html>
    

    注意:

    • 直接嵌入其他域(localhots:10001)下的URL会报错,所以需要加载完成替换为当前域的URL(localhots:10000),proxy.html为空白页面,只为解决该问题;
      在这里插入图片描述
    • 重新设置 src(http://localhost:10000/proxy.html)后导致页面不断刷新,所以通过 state 来控制;
    • 全部获取完结果后,清除该 iframe。

    方式五:window.postMessage()

    HTML5新特性,可以用来向其他所有的 window 对象发送消息。需要注意的是我们必须要保证所有的脚本执行完才发送 MessageEvent,如果在函数执行的过程中调用了它,就会让后面的函数超时无法执行。

    下述代码实现了跨域存储localStorage

    下述用端口:10000表示 — domainA;10001表示 — domainB

    <!-- localhost:10000 -->
    <iframe src="http://localhost:10001/msg.html" name="myPostMessage" style="display:none;">
    </iframe>
    
    <script>
      function main() {
          LSsetItem('test', 'Test: ' + new Date());
          LSgetItem('test', function(value) {
              console.log('value: ' + value);
          });
          LSremoveItem('test');
      }
    
      var callbacks = {};
      window.addEventListener('message', function(event) {
          if (event.source === frames['myPostMessage']) {
              console.log(event)
              var data = /^#localStorage#(\d+)(null)?#([\S\s]*)/.exec(event.data);
              if (data) {
                  if (callbacks[data[1]]) {
                      callbacks[data[1]](data[2] === 'null' ? null : data[3]);
                  }
                  delete callbacks[data[1]];
              }
          }
      }, false);
    
      var domain = '*';
      // 增加
      function LSsetItem(key, value) {
          var obj = {
              setItem: key,
              value: value
          };
          frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
      }
      // 获取
      function LSgetItem(key, callback) {
          var identifier = new Date().getTime();
          var obj = {
              identifier: identifier,
              getItem: key
          };
          callbacks[identifier] = callback;
          frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
      }
      // 删除
      function LSremoveItem(key) {
          var obj = {
              removeItem: key
          };
          frames['myPostMessage'].postMessage(JSON.stringify(obj), domain);
      }
    </script>
    
    <!-- localhost:10001 -->
    <script>
      window.addEventListener('message', function(event) {
        console.log('Receiver debugging', event);
        if (event.origin == 'http://localhost:10000') {
          var data = JSON.parse(event.data);
          if ('setItem' in data) {
            localStorage.setItem(data.setItem, data.value);
          } else if ('getItem' in data) {
            var gotItem = localStorage.getItem(data.getItem);
            event.source.postMessage(
              '#localStorage#' + data.identifier +
              (gotItem === null ? 'null#' : '#' + gotItem),
              event.origin
            );
          } else if ('removeItem' in data) {
            localStorage.removeItem(data.removeItem);
          }
        }
      }, false);
    </script>
    

    注意Safari下会报错:

    Blocked a frame with origin “http://localhost:10001” from accessing a frame with origin “http://localhost:10000”. Protocols, domains, and ports must match.

    避免该错误,可以在Safari浏览器中勾选 开发菜单 => 停用跨域限制。或者只能使用服务器端转存的方式实现,因为Safari浏览器默认只支持CORS跨域请求。

    方式六:修改document.domain跨子域

    前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用 document.domain 进行跨域,所以只能跨子域

    根域范围内,允许把 domain 属性的值设置为它的上一级域。例如,在 “aaa.xxx.com” 域内,可以把 domain 设置为 “xxx.com” 但不能设置为 “xxx.org” 或者 “com”。

    现在存在两个域名aaa.xxx.com和bbb.xxx.com。在aaa下嵌入bbb的页面,由于其 document.name不一致,无法在aaa下操作bbb的js。可以在aaa和bbb下通过js将 document.name = 'xxx.com'; 设置一致,来达到互相访问的作用。

    方式七:WebSocket

    WebSocket protocol 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很棒的实现。相关文章,请查看:WebSocketWebSocket-SockJS

    需要注意: WebSocket 对象不支持 DOM 2 级事件侦听器,必须使用 DOM 0 级语法分别定义各个事件。

    方式八:代理

    同源策略是针对浏览器端进行的限制,可以通过服务器端来解决该问题
    DomainA客户端(浏览器) => DomainA服务器 => DomainB服务器 => DomainA客户端(浏览器)
    实现HTTP、HTTPS代理请参照: 创建HTTP与HTTPS服务器与客户端

    展开全文
  • 前端做跨域有哪些方式,后端做跨域请求又有哪些方式 我知道可以前端将跨域请求的域名传给后端,然后后端做跨域请求,好像是用get_file_contents方式 还有哪些方式
  • Springboot处理CORS跨域请求的三种方法

    万次阅读 多人点赞 2020-06-08 11:23:52
    跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。 之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。 浏览器出于...

    前言

    Springboot跨域问题,是当前主流web开发人员都绕不开的难题。但我们首先要明确以下几点

    • 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境
    • 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
    • 之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。

    浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。换句话说,浏览器安全的基石是同源策略。

    同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

    目录

     

    一、什么是CORS?

    CORS Header

    二、SpringBoot跨域请求处理方式

    方法一、直接采用SpringBoot的注解@CrossOrigin(也支持SpringMVC)

    方法二、处理跨域请求的Configuration

    方法三、采用过滤器(filter)的方式

    总结



    先给出一个熟悉的报错信息,让你找到家的感觉~

    Access to XMLHttpRequest at 'http://192.168.1.1:8080/app/easypoi/importExcelFile' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    一、什么是CORS?

    CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

    它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。
     

    CORS Header

    • Access-Control-Allow-Origin: http://www.xxx.com
    • Access-Control-Max-Age:86400
    • Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, DELETE
    • Access-Control-Allow-Headers: content-type
    • Access-Control-Allow-Credentials: true

    含义解释:

    CORS Header属性 解释
    Access-Control-Allow-Origin 允许http://www.xxx.com域(自行设置,这里只做示例)发起跨域请求
    Access-Control-Max-Age 设置在86400秒不需要再发送预校验请求
    Access-Control-Allow-Methods 设置允许跨域请求的方法
    Access-Control-Allow-Headers 允许跨域请求包含content-type
    Access-Control-Allow-Credentials 设置允许Cookie

     

     

     

     

     

     

     

    二、SpringBoot跨域请求处理方式

    方法一、直接采用SpringBoot的注解@CrossOrigin(也支持SpringMVC)

    简单粗暴的方式,Controller层在需要跨域的类或者方法上加上该注解即可

     

    /**
     * Created with IDEA
     *
     * @Author Chensj
     * @Date 2020/5/8 10:28
     * @Description xxxx控制层
     * @Version 1.0
     */
    @RestController
    @CrossOrigin
    @RequestMapping("/situation")
    public class SituationController extends PublicUtilController {
    
        @Autowired
        private SituationService situationService;
        // log日志信息
        private static Logger LOGGER = Logger.getLogger(SituationController.class);
    
    
    
    }

    但每个Controller都得加,太麻烦了,怎么办呢,加在Controller公共父类(PublicUtilController)中,所有Controller继承即可。

    /**
     * Created with IDEA
     *
     * @Author Chensj
     * @Date 2020/5/6 10:01
     * @Description
     * @Version 1.0
     */
    @CrossOrigin
    public class PublicUtilController {
    
        /**
         * 公共分页参数整理接口
         *
         * @param currentPage
         * @param pageSize
         * @return
         */
        public PageInfoUtil proccedPageInfo(String currentPage, String pageSize) {
    
            /* 分页 */
            PageInfoUtil pageInfoUtil = new PageInfoUtil();
            try {
                /*
                 * 将字符串转换成整数,有风险, 字符串为a,转换不成整数
                 */
                pageInfoUtil.setCurrentPage(Integer.valueOf(currentPage));
                pageInfoUtil.setPageSize(Integer.valueOf(pageSize));
            } catch (NumberFormatException e) {
            }
            return pageInfoUtil;
        }
    
    }

     

    当然,这里虽然指SpringBoot,SpringMVC也是同样的,但要求在Spring4.2及以上的版本。另外,如果SpringMVC框架版本不方便修改,也可以通过修改tomcat的web.xml配置文件来处理,请参照另一篇博文(nginx同理)

    SpringMVC使用@CrossOrigin使用场景要求

    • jdk1.8+
    • Spring4.2+

     

    方法二、处理跨域请求的Configuration

    增加一个配置类,CrossOriginConfig.java。继承WebMvcConfigurerAdapter或者实现WebMvcConfigurer接口,其他都不用管,项目启动时,会自动读取配置。

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    /**
     * AJAX请求跨域
     * @author Mr.W
     * @time 2018-08-13
     */
    @Configuration
    public class CorsConfig extends WebMvcConfigurerAdapter {
        static final String ORIGINS[] = new String[] { "GET", "POST", "PUT", "DELETE" };
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);
        }

    方法三、采用过滤器(filter)的方式

    同方法二加配置类,增加一个CORSFilter 类,并实现Filter接口即可,其他都不用管,接口调用时,会过滤跨域的拦截。

     @Component
    public class CORSFilter implements Filter {
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletResponse res = (HttpServletResponse) response;
            res.addHeader("Access-Control-Allow-Credentials", "true");
            res.addHeader("Access-Control-Allow-Origin", "*");
            res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
            res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
            if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
                response.getWriter().println("ok");
                return;
            }
            chain.doFilter(request, response);
        }
        @Override
        public void destroy() {
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }

    总结

    好了,关于Springboot比较常用的解决跨域问题方式都已经分享给您了,希望对老铁有所帮助。

     

    展开全文
  • 但是有时候跨域请求资源是合理的需求,本文尝试从多篇文章中汇总至今存在的所有跨域请求解决方案。 跨域请求 首先需要了解的是同源和跨源的概念。对于相同源,其定义为:如果协议、端口(如果指定了一个)和...

    同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。但是有时候跨域请求资源是合理的需求,本文尝试从多篇文章中汇总至今存在的所有跨域请求解决方案。

    跨域请求

    首先需要了解的是同源和跨源的概念。对于相同源,其定义为:如果协议、端口(如果指定了一个)和主机对于两个页面是相同的,则两个页面具有相同的源。只要三者之一任意一点有不同,那么就为不同源。当一个资源从与该资源本身所在的服务器的域或端口不同的域或不同的端口请求一个资源时,资源会发起一个跨域 HTTP 请求。而有关跨域请求受到限制的原因可以参考如下 MDN 文档片段:

    跨域不一定是浏览器限制了发起跨站请求,而也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。最好的例子是 CSRF 跨站攻击原理,请求是发送到了后端服务器无论是否跨域!注意:有些浏览器不允许从 HTTPS 的域跨域访问 HTTP,比如 Chrome 和 Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例。

    解决方法汇总

    以下我们由简及深介绍各种存在的跨域请求解决方案,包括 document.domain, location.hash, window.name, window.postMessage, JSONP, WebSocket, CORS 。

    document.domain

    document.domain 的作用是用来获取/设置当前文档的原始域部分,例如:

    // 对于文档 www.example.xxx/good.html 
    document.domain=”www.example.xxx”

    // 对于URI http://developer.mozilla.org/en/docs/DOM 
    document.domain=”developer.mozilla.org” 
    如果当前文档的域无法识别,那么 domain 属性会返回 null。

    在根域范围内,Mozilla允许你把domain属性的值设置为它的上一级域。例如,在 developer.mozilla.org 域内,可以把domain设置为 “mozilla.org” 但不能设置为 “mozilla.com” 或者”org”。

    因此,若两个源所用协议、端口一致,主域相同而二级域名不同的话,可以借鉴该方法解决跨域请求。

    比如若我们在http://a.github.io 页面执行以下语句:

    document.domain = “github.io” 
    那么之后页面对 github.io 发起请求时页面则会成功通过对 github.io 的同源检测。比较直接的一个操作是,当我们在 a.github.io 页面中利用 iframe 去加载 github.io 时,通过如上的赋值后,我们可以在 a.github.io 页面中去操作 iframe 里的内容。

    我们同时考虑另一种情况:存在两个子域名 a.github.io 以及 b.github.io , 其中前者域名下网页 a.html 通过 iframe 引入了后者域名下的 b.html,此时在 a.html 中是无法直接操作 b.html 的内容的。

    同样利用 document.domain ,我们在两个页面中均加入

    document.domain=’github.io’ 
    这样在以上的 a.html 中就可以操作通过 iframe 引入的 b.html 了。

    document.domain的优点在于解决了主语相同的跨域请求,但是其缺点也是很明显的:比如一个站点受到攻击后,另一个站点会因此引起安全漏洞;若一个页面中引入多个 iframe,想要操作所有的 iframe 则需要设置相同的 domain。

    location.hash

    location.hash 是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。例如:

    // 对于页面 http://example.com:1234/test.htm#part2 
    location.hash = “#part2” 
    同时,由于我们知道改变 hash 并不会导致页面刷新,所以可以利用 hash 在不同源间传递数据。

    假设 github.io 域名下 a.html 和 shaonian.eu 域名下 b.html 存在跨域请求,那么利用 location.hash 的一个解决方案如下:

    a.html 页面中创建一个隐藏的 iframe, src 指向 b.html,其中 src 中可以通过 hash 传入参数给 b.html 
    b.html 页面在处理完传入的 hash 后通过修改 a.html 的 hash 值达到将数据传送给 a.html 的目的 
    a.html 页面添加一个定时器,每隔一定时间判断自身的 location.hash 是否变化,以此响应处理 
    以上步骤中需要注意第二点:如何在 iframe 页面中修改 父亲页面的 hash 值。由于在 IE 和 Chrome 下,两个不同域的页面是不允许 parent.location.hash 这样赋值的,所以对于这种情况,我们需要在父亲页面域名下添加另一个页面来实现跨域请求,具体如下:

    假设 a.html 中 iframe 引入了 b.html, 数据需要在这两个页面之间传递,且 c.html 是一个与 a.html 同源的页面 
    a.html 通过 iframe 将数据通过 hash 传给 b.html 
    b.html 通过 iframe 将数据通过 hash 传给 c.html 
    c.html 通过 parent.parent.location.hash 设置 a.html 的 hash 达到传递数据的目的 
    location.bash方法的优点在于可以解决域名完全不同的跨域请求,并且可以实现双向通讯;而缺点则包括以下几点:

    利用这种方法传递的数据量受到 url 大小的限制,传递数据类型有限 
    由于数据直接暴露在 url 中则存在安全问题 
    若浏览器不支持 onhashchange 事件,则需要通过轮训来获知 url 的变化 
    有些浏览器会在 hash 变化时产生历史记录,因此可能影响用户体验 
    window.name

    该属性用于获取/设置窗口的名称。其特征在于:一个窗口的生命周期内,窗口载入的所有页面共享该值,且都具有对该属性的读写权限。这意味着如果不修改该值,那么在不同页面加载之后该值也不会变,且其支持长达 2MB 的存储量。

    利用该特性我们可以将跨域请求用如下步骤解决:

    在 a.github.io/a.html 中创建 iframe 指向 b.github.io/b.html (页面会将自身的 window.name 附在 iframe 上) 
    给 a.github.io/a.html 添加监听 iframe 的 onload 事件,在该事件中将 iframe 的 src 设置为本地域的代理文件(代理文件和a.html处于同一域下,可以相互通信),同时可以传出 iframe 的 name 值 
    获取数据后销毁 iframe,释放内存,同时也保证了安全 
    window.name的优势在于巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

    window.postMessage

    HTML5 为了解决这个问题,引入了一个全新的 API:跨文档通信 API(Cross-document messaging)。这个 API 为 window 对象新增了一个 window.postMessage 方法,允许跨窗口通信,不论这两个窗口是否同源。

    API 的详细使用方法请见 MDN 。

    JSONP

    JSONP, 全称 JSON with Padding,是使用 AJAX 实现的请求不同源的跨域。其基本原理:网页通过添加一个

    // 当前页面 a.com/a.html
    <script type="text/javascript">
    //回调函数
    function callback(data) {
        alert(data.message);
    }
    </script>
    <script type="text/javascript" src="http://b.com/test.js"></script>
    
    // test.js
    // 调用callback函数,并以json数据形式作为阐述传递,完成回调
    callback({message:"success"});
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    为了保证 script 的灵活,我们可以通过 JavaScript 动态创建 script 标签,并通过 HTTP 参数向服务器传入回调函数名,案例如下所示:

    <script type="text/javascript">
        // 添加<script>标签的方法
        function addScriptTag(src){
            var script = document.createElement('script');
            script.setAttribute("type","text/javascript");
            script.src = src;
            document.body.appendChild(script);
        }
    
        window.onload = function(){
            // 搜索apple,将自定义的回调函数名result传入callback参数中
            addScriptTag("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=apple&callback=result");
    
        }
        // 自定义的回调函数result
        function result(data) {
            // 我们就简单的获取apple搜索结果的第一条记录中url数据
            alert(data.responseData.results[0].unescapedUrl);
        }
    </script>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    jQuery 有相应的 JSONP 的实现方法,见 API 。

    JSONP的优点在于简单适用,老式浏览器全部支持,服务器改造小。不需要XMLHttpRequest或ActiveX的支持;但缺点是只支持 GET 请求。

    WebSocket

    WebSocket 协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

    CORS

    CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

    跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。其需要服务端和客户端同时支持。

    跨域资源共享标准( cross-origin sharing standard )允许在下列场景中使用跨域 HTTP 请求:

    由 XMLHttpRequest 或 Fetch 发起的跨域 HTTP 请求

    Web 字体 (CSS 中通过 @font-face 使用跨域字体资源), 因此,网站就可以发布 TrueType 字体资源,并只允许已授权网站进行跨站调用

    WebGL 贴图

    使用 drawImage 将 Images/video 画面绘制到 canvas

    样式表(使用 CSSOM)

    Scripts (未处理的异常)

    CORS 存在以下三种主要场景,分别是 简单请求,预检请求和附带身份凭证的请求 。

    简单请求 :若只使用 GET, HEAD 或者 POST 请求,且除 CORS 安全的首部字段集合外,无人为设置该集合之外的其他首部字段,同时 Content-Type 值属于下列之一,那么该请求则可以被视为简单请求: 
    application/x-www-form-urlencoded 
    multipart/form-data 
    text/plain 
    此情况下,若服务端返回的 Access-Control-Allow-Origin: * ,则表明该资源可以被任意外域访问。若要指定仅允许来自某些域的访问,需要将 * 设定为该域,例如:

    Access-Control-Allow-Origin: http://foo.example 
    预检请求 :与前述简单请求不同,该要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。当请求满足以下三个条件任意之一时, 即应首先发送预检请求: 
    使用了 PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH 中任一的 HTTP 方法 
    人为设置了对 CORS 安全的首部字段集合之外的其他首部字段 
    Content-Type 的值不属于下列之一 
    application/x-www-form-urlencoded 
    multipart/form-data 
    text/plain 
    预检请求完成之后(通过 OPTIONS 方法实现),才发送实际请求。一个示范 HTTP 请求如下所示:

    var invocation = new XMLHttpRequest();
    var url = 'http://bar.other/resources/post-here/';
    var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
    
    function callOtherDomain(){
      if(invocation)
        {
          invocation.open('POST', url, true);
          invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
          invocation.setRequestHeader('Content-Type', 'application/xml');
          invocation.onreadystatechange = handler;
          invocation.send(body); 
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    附带身份凭证的请求 :这种方式的特点在于能够在跨域请求时向服务器发送凭证请求,例如 Cookies (withCredentials 标志设置为 true)。 
    一般而言,对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。但是需要注意的是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。

    附带身份凭证的请求与通配符

    对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。

    这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。

    另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。

    MDN 引例如下:

    var invocation = new XMLHttpRequest();
    var url = 'http://bar.other/resources/credentialed-content/';
    
    function callOtherDomain(){
      if(invocation) {
        invocation.open('GET', url, true);
        invocation.withCredentials = true;
        invocation.onreadystatechange = handler;
        invocation.send(); 
      }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其实由上我们知道, CORS 的优点也非常明显:CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案。

    以上就是所有的跨域请求解决方案,根据实际生产环境,总有一款适合你。

    展开全文
  • 跨域请求会不会在你的问题名单中? 这里有有张摘自网络的图片 简述跨域问题 SpringBoot跨域请求 1、直接采用SpringBoot的注解@CrossOrigin 2、处理跨域请求的Configuration CrossOriginConfig.java import org....
  • 网站跨域请求的解决方案

    万次阅读 2019-04-23 14:03:27
    网站跨域请求的五种解决方案: 1、使用JSONP解决跨域问题(不推荐,因为支支持get请求,不支持post请求) 2、使用httpClient或者HttpUrlConnection进行内部转发请求响应(不推荐,因为需要多请求一次请求) 3、...
  • 跨域请求CORS

    2017-10-14 19:32:27
    跨域请求问题解决什么叫做跨域请求 跨域是指 请求的协议/端口号/域名 任何一个不同都可以被称为跨域请求,例如 ajax 异步向不同的域请求数据,又或者 js 获取页面中不同域的框架中(iframe)的数据。分布式项目中应用...
  • 一、什么是跨域请求? 跨域: 简单来说就是 A 网站的 javascript 代码试图访问 B 网站,包括提交内容和获取内容。这显然是不安全的。为此,浏览器的鼻祖:网景(Netscape)公司提出了优秀的解决方案:著名的浏览器...
  • ajax请求报错 php开启跨域请求

    万次阅读 2019-07-23 09:40:11
    在被请求的php文件中加入请求头部 header('Access-Control-Allow-Origin: *');
  • jQuery的AJAX跨域请求的实现: 这边文章写得很好: http://justcoding.iteye.com/blog/1366102 阅读jQuery的源码可知,用设置 dataType: "jsonp"进行跨域请求时,jQuery会判断请求的域是否和页面属于同域,如果...
  • 跨域请求及跨域携带Cookie解决方案

    万次阅读 2018-08-08 17:30:48
    跨域请求及跨域携带Cookie解决方案 Web项目前后端分离开发时,经常会遇到跨域请求和跨域携带Cookie的相关问题: 跨域请求 服务端可以根据实际需求修改下面设置,以Java代码为做示例: //允许跨域的域名,...
  • 火狐浏览器提示已拦截跨域请求,解决发放如下: 1.在火狐浏览器地址栏输入 about:preferences#privacy 2.证书 -&gt; 查看证书 -&gt; 添加例外 -&gt; 输入要添加的url -&gt; 获取...
  • SpringBoot跨域请求

    千次阅读 2018-05-27 19:00:24
    在软件开发过程中,尤其是现在的前后端分离开发,跨域请求是很普通的事情,我这个只是简单的将所有的跨域请求都接受,如若有大佬有更好的解决方案欢迎分享 问题: 在请求的时候,前端使用js进行ajax请求未能接收...
  • 由于浏览器的同域安全策略(the same-origin security policy),这种跨域请求会被禁止。 eg.如下为在一个站点向另一个站点发送请求。 跨域问题解决 (1)@CrossOrigin:该注解有一个origins参数,可配置允许进行...
  • 跨域请求何谓跨域请求?简单来说,是浏览器的一种自我保护机制。Web请求连接中,有三大要素:地址ip、端口port、协议http/https,只要其中有一个不一致,浏览器将视其为跨域请求跨域请求跨域请求不是一个新鲜的...
  • Vue实现跨域请求

    万次阅读 多人点赞 2018-09-13 15:56:35
    实现跨域请求有两种方式: 1、fetch (1)在App.vue中使用created方法创建fetch,将域名及方法等创建,如下图 (2)在config配置文件中的index.js中的跨域区域中写入如下代码: (3)完善信息,将接口相应的...
  • JavaScript跨域请求

    2018-03-22 10:53:13
    个人博客:打开链接 1 什么是跨域 Js为了安全有一个限制,...1、在js中不能跨域请求数据,js可以跨域请求js片段。 2、可以把数据包装成js片段。可以把数据使用js方法来包装,形成一条方法的调用语句。 3、可以...
  • https跨域请求http数据

    万次阅读 2018-06-28 18:03:40
    A站:https://www.aaa.comB站:http://www.bbb.com直接用ajax跨域请求返回数据因为不是https协议网站 ( B站没有https证书 ) 返回的数据或资源所以会被A站拦截阻挡,自己想到解决办法写一个API做中转数据,在A站内些一...
  • JSONP跨域请求

    千次阅读 2018-12-18 00:00:47
    显然同源策略限制了前端的向外拓展的能力,实际应用中可以使用跨域请求来实现对外拓展。跨域顾名思义就是请求域名不同,如果考虑到细节,同一域名不同端口、同一域名不同协议也算跨域。举个例子,当前项目的请求是...
  • nginx跨域请求

    万次阅读 2018-01-30 12:37:29
    nginx跨域请求 Access-Control-Allow-Origin * 当出现403跨域错误’Access-Control-Allow-Origin’,需要给Nginx服务器配置响应的header参数 解决方法 #修改nginx.conf文件 server { add_header Access-...
  • ajax跨域请求

    千次阅读 2018-12-01 13:56:34
    最后导致虽然请求200,但是不会返回任何数据,事实上简单来说请求同一个域名下的url或者说用不带http的绝对路径和相对路径请求是没有任何问题的,如果请求外部资源,那么这就称为跨域请求。 跨域问题的来源于...
  • 现代浏览器处于安全的考虑,在http/https请求时必须遵守同源策略,否则即使跨域的http/https 请求,... 使用 JSONP 来支持跨域的请求,JSONP 实现跨域请求的原理简单的说,就是动态创建 script 标签,然后利用 ...
  • egg跨域请求

    千次阅读 2018-11-02 15:46:41
    web端访问服务器,存在跨域请求问题,egg作为服务端,需要开放请求域,方法如下: 1、安装egg-cors npm i egg-cors -S 2、在config/plugin.js声明 exports.cors = { enable: true, package: 'egg-cors', }; ...
  • Ajax跨域请求

    千次阅读 2018-03-27 22:51:49
    Js是不能跨域请求。出于安全考虑,js设计时不可以跨域。 什么是跨域 跨域 指的时浏览器前端js请求服务端时,如果前端的发布地址和端口与请求的服务端地址和端口不一样。 以下情况属于跨域: 1、域名不同时。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,346
精华内容 12,138
关键字:

跨域请求