当前位置: 首页 > news >正文

JavaScript 常用的几种跨域方式实现原理

前后端进行数据交互的时,会经常碰到请求跨域的问题,以下几种为常见解决方式。

  一、跨域的解决方案

    1、JSONP

      1)原理:利用 script 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP 请求一定需要对方的服务器做支持才可以。

      2)JSONP 和 AJAX 对比

         JSONP 和 AJAX 相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但 AJAX 属于同源策略,JSONP 属于非同源策略(跨域请求)。

      3)JSONP 优缺点

         JSONP 优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持 get 方法具有局限性,不安全可能会遭受 XSS 攻击。

      4)JSONP 的实现流程

        声明一个回调函数,其函数名(如 show)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的 data)。创建一个script标签,把那个跨域的 API 数据接口地址,赋值给 script 的 src,还要在这个地址中向服务器传递该函数名(可以通过问号传参:?callback=show)。服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是 show,它准备好的数据是show(我不爱你)。最后服务器把准备的数据通过 HTTP 协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP 函数(百度上有很多JSONP封装的函数可以搜一下)

      5)jQuery 的 jsonp 形式

        JSONP 都是 GET 和异步请求的,不存在其他的请求方式和同步请求,且 jQuery 默认就会给 JSONP 的请求清除缓存。

        $.ajax({

        url:"[http://crossdomain.com/jsonServerResponse](http://crossdomain.com/jsonServerResponse)",

        dataType:"jsonp",

        type:"get",//可以省略

          jsonpCallback:"show",//->自定义传递给服务器的函数名,而不是使用jQuery自动生成的,可省略

          jsonp:"callback",//->把传递函数名的那个形参callback,可省略

          success:function (data){

           console.log(data);}

         });//相对来说用JQuery的JSONP格式的多一点

    2、CORS

       CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求和复杂请求。

       1)、简单请求

           只要满足以下两大条件就属于简单请求

           条件一:

           GET,POST,HEAD

           条件二:

            Content-Type的值仅限以下三种

          text/plain
          multipart/form-data
          application/x-www-form-urlencoded

          请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。

      2)、非简单请求

          使用了下面任一 HTTP 方法:

          PUT

                               DELETE

CONNECT

OPTIONS

TRACE

PATCH

Content-Type 的值不属于下列之一:

application/x-www-form-urlencoded

multipart/form-data

text/plain

当发生符合非简单请求(预检请求)的条件时,浏览器会自动先发送一个options请求,如果发现服务器支持该请求,则会将真正的请求发送到后端,反之,如果浏览器发现服务端并不支持该请求,则会在控制台抛出错误,如下:

          假如发送成功,则会在头部多返回以下字段        

Access-Control-Allow-Origin: http://localhost:3001 //该字段表明可供那个源跨域
Access-Control-Allow-Methods: GET, POST, PUT // 该字段表明服务端支持的请求方法
Access-Control-Allow-Headers: X-Custom-Header // 实际请求将携带的自定义请求首部字段

    3、ngnix反向代理      

实现原理类似于 Node 中间件代理,需要你搭建一个中转 nginx 服务器,用于转发请求。

使用 nginx 反向代理实现跨域,是最简单的跨域方式。只需要修改 nginx 的配置即可解决跨域问题,支持所有浏览器,支持 session,不需要修改任何代码,并且不会影响服务器性能。

实现思路:通过 nginx 配置一个代理服务器(域名与 domain1 相同,端口不同)做跳板机,反向代理访问 domain2 接口,并且可以顺便修改 cookie 中 domain 信息,方便当前域 cookie 写入,实现跨域登录。

先下载nginx,然后将 nginx 目录下的 nginx.conf 修改如下:

// proxy服务器
server {
 listen  80;
 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;
 }
}

     最后通过命令行nginx -s reload启动 nginx

     

var xhr = new XMLHttpRequest();`
// 前端开关:浏览器是否读写cookie`
xhr.withCredentials = true;`
// 访问nginx中的代理服务器`
xhr.open('get', '[http://www.domain1.com:81/?user=admin](http://www.domain1.com:81/?user=admin)', true);`
xhr.send();`
// server.js
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
 var params = qs.parse(req.url.substring(2));
 // 向前台写cookie
 res.writeHead(200, {
  'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取
 });
 res.write(JSON.stringify(params));
 res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');             

总的来说,使用CORS简单请求,非常容易,对于前端来说无需做任何配置,与发送普通ajax请求无异。唯一需要注意的是,需要携带cookie信息时,需要将withCredentials设置为true即可。CORS的配置,完全在后端设置,配置起来也比较容易,目前对于大部分浏览器兼容性也比较好。CORS优势也比较明显,可以实现任何类型的请求


转载:https://my.oschina.net/u/3972188/blog/3009785

      

转载于:https://www.cnblogs.com/HoldSelf/p/10442010.html

相关文章:

  • NYOJ 简单数据结构
  • js对象的深浅拷贝
  • ★Kali信息收集~4.DNS系列
  • Promise面试题2实现异步串行执行
  • Flex的一些总结
  • SAP ERP和C4C Account和Contact的双向同步
  • Spring源码解析—— ClassPathResource类
  • Angular6错误 Service: No provider for Renderer2
  • 01串(dp)
  • 通用排序工具类
  • Python 进行 URL 跳转
  • 安卓使用Root权限实现后台模拟全局按键、触屏事件方法(类似按键精灵)
  • 第13期 DApp 榜单 :来,吃我这波安利
  • java swing启动时窗口最大化
  • 一行代码迁移TensorFlow 1.x到TensorFlow 2.0
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • const let
  • ES6之路之模块详解
  • flutter的key在widget list的作用以及必要性
  • github从入门到放弃(1)
  • golang中接口赋值与方法集
  • HTML中设置input等文本框为不可操作
  • Joomla 2.x, 3.x useful code cheatsheet
  • mysql常用命令汇总
  • ng6--错误信息小结(持续更新)
  • node-glob通配符
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • SOFAMosn配置模型
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 阿里云前端周刊 - 第 26 期
  • 初识MongoDB分片
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 实习面试笔记
  • 你对linux中grep命令知道多少?
  • Android开发者必备:推荐一款助力开发的开源APP
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • #NOIP 2014# day.1 T2 联合权值
  • (floyd+补集) poj 3275
  • (篇九)MySQL常用内置函数
  • (十一)c52学习之旅-动态数码管
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET单元测试
  • .net知识和学习方法系列(二十一)CLR-枚举
  • @RequestBody与@ModelAttribute
  • @vue/cli脚手架
  • [ linux ] linux 命令英文全称及解释
  • [20170705]lsnrctl status LISTENER_SCAN1
  • [C++] new和delete
  • [datastore@cyberfear.com].Elbie、[thekeyishere@cock.li].Elbie勒索病毒数据怎么处理|数据解密恢复