跨域解决之JSONP和CORS的详细介绍


Posted in Javascript onNovember 21, 2018

JSONP跨域和CORS跨域

什么是跨域?

跨域:指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的,是浏览器的安全限制!

同源策略

同源策略:域名、协议、端口均相同。

浏览器执行JavaScript脚本时,会检查这个脚本属于那个页面,如果不是同源页面,就不会被执行。

JSONP跨域

只支持GET请求,不支持POST等其它请求,也不支持复杂请求,只支持简单请求。

CORS跨域

支持所有的请求,包含GET、POST、OPTOIN、PUT、DELETE等。既支持复杂请求,也支持简单请求。

JSONP和CORS跨域理解

使用目的: JSONP与CORS的使用目的相同,并且都需要服务端和客户端同时支持,但CORS的功能更加强大。
JSONP(json with padding 填充式json):利用了使用src引用静态资源时不受跨域限制的机制。主要在客户端搞一个回调做一些参数接收与操作的处理,并把这个回调函数告知服务器,而服务器端需要做的是按照JavaScript的语法把数据放到约定好的回调函数之中即可,jQuery很早之前就已经把JSONP语法糖化了,使用起来会更加方便。
CORS(Cross-origin resource sharing 跨域资源共享):依附于AJAX,通过添加HTTP Header部分字段请求与获取有权限访问的资源。CORS对开发者是透明的,因为浏览器会自动根据请求的情况(简单和复杂)做出不同的处理。CORS的关键是服务器端的配置支持,由于CORS是W3C中一项较“新”的方案,以至于各大网页解析引擎还没有对齐进行严格规格的实现,所以不同引擎下可能会有一些不一致。

JSONP和CORS的优缺点

1. JSONP的主要优势在于对浏览器的支持较好;虽然目前主流浏览器都支持CORS,但IE9及以下不支持CORS。

2. JSONP只能用于获取资源(即只读,类似于GET请求);CORS支持所有类型的HTTP请求,功能完善。(这点JSONP被玩虐,但大部分情况下GET已经能满足需求了)
JSONP的错误处理机制并不完善,我们没办法进行错误处理;而CORS可以通过onerror事件监听错误,并且浏览器控制台会看到报错信息,利于排查。

3. JSONP只会发一次请求;而对于复杂请求,CORS会发两次请求。

4. 始终觉得安全性这个东西是相对的,没有绝对的安全,也做不到绝对的安全。毕竟JSONP并不是跨域规范,它存在很明显的安全问题:callback参数注入和资源访问授权设置。CORS好歹也算是个跨域规范,在资源访问授权方面进行了限制(Access-Control-Allow-Origin),而且标准浏览器都做了安全限制,比如拒绝手动设置origin字段,相对来说是安全了一点。但是回过头来看一下,就算是不安全的JSONP,我们依然可以在服务端端进行一些权限的限制,服务端和客户端也都依然可以做一些注入的安全处理,哪怕被攻克,它也只能读一些东西。就算是比较安全的CORS,同样可以在服务端设置出现漏洞或者不在浏览器的跨域限制环境下进行攻击,而且它不仅可以读,还可以写。

应用场景

  • 如果需要兼容IE低版本浏览器,无疑,JSONP。
  • 如果需要对服务端资源进行操作,无疑,CORS。
  • 其他情况的话,根据自己的对需求的分析来决定和使用。

相同协议、域名、端口下

  • 页面在 http://localhost:3000/0
  • 服务在 http://localhost:3000/1
  • 控制台能正常输出 {name: '', sex: '', _stamp: ''}

views/0.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>

  </style>
</head>
<body>
  <form action="/" onsubmit="return false">
    <label for="name">NAME</label><input type="text" id="name" name="name"><br>
    <label for="sex">SEX</label><input type="text" id="sex" name="sex"><br>
    <input type="submit" value="SUBMIT">
  </form>
  <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  <script>
    $('form').on('submit', function(){
      $.ajax({
        url: 'http://localhost:3000/1',
        data: {
          name: $('#name').val(),
          sex: $('#sex').val()
        },
        success: function(data){
          console.log(data);
        }
      })
    })
  </script>
</body>
</html>

serve.js

const server = require('express')();

server.set('view engine', 'ejs');

server.get('/0', (req, res) => {
  res.render('0.ejs', {});
})

server.get('/1', (req, res) => {
  let {name, sex} = req.query;
  res.send({name, sex, _stamp: + new Date});
})

server.listen(3000);

JSONP

把0.ejs改为0.hmtl,直接打开或者在http://localhost:3001/views/0.html打开(3000端口被占用时运行$ browser-sync start --server --files '**')

控制台报错 Access to XMLHttpRequest at 'http://localhost:3000/1?name=&sex=' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

jQuery 的 JSONP

0.html 的脚本改为

function jCb(data){ // 这个函数和ajax 的 success 同样可以操作 data
  console.log('你要的', data);
}
$('form').on('submit', function(){
  $.ajax({
    url: 'http://localhost:3000/1',
    data: {
      name: $('#name').val(),
      sex: $('#sex').val()
    },
    dataType: 'jsonp',
    jsonpCallback: 'jCb', // 服务端 req.query.callback = 'jCb'
    success: function(data){
      console.log(data);
    }
  })
})

server.js 注意返回客户端的字符串的拼接

const server = require('express')();
server.get('/1', (req, res) => {
  let {name, sex, callback} = req.query;
  var data = "{name: '', sex: '', _stamp: ''}"; // 然后再在单引号处拼接
    data = "{name: '" + name + "', sex: '" + sex + "', _stamp:' " + Date.now() + "'}";
    data = `{name: '${name}', sex: '${sex}', _stamp: '${+ new Date}'}`

  var resStr = callback + "()"
    resStr = callback + "(" + data + ")"
  console.log(callback, typeof callback); // jCb string
  console.log(resStr, typeof resStr); // jCb({name:'',sex:'',_stamp:'1542456915800'}) string
  res.send(resStr);
})

server.listen(3000);

利用 script 标签

0.html

<script>
  function jCb(data) {
    console.log("jsonpCallback: " + data.name)
  }
</script>
<script src = 'http://localhost:3000/1?jsonp=jsonpCallback'></script>
server.js

server.get('/1', (req, res) => {
  var data = 'var data = {name: $("#name").val(), sex: $("#sex").val(), _stamp: + new Date };'
  var debug = 'console.log(data);'
  var callback = '$("form").submit(function(){' + data + req.query.jsonp + '(data);' + debug + '});'
  res.send(callback);
})

CORS

html 代码还是最初的代码,server.js 改变

server.get('/1', (req, res) => {
  // 设置可以请求的域名,"*" 代表所有域名
  res.header("Access-Control-Allow-Origin", "http://localhost:3001");

  // 设置所允许的HTTP请求方法。
  res.header("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE");

  // 字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段。
  res.header("Access-Control-Allow-Headers", "x-requested-with, accept, origin, content-type");

  // 服务器收到请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

  // Content-Type表示具体请求中的媒体类型信息。
  res.header("Content-Type", "application/json;charset=utf-8");

  // 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。
  // 当设置成允许请求携带cookie时,需要保证"Access-Control-Allow-Origin"是服务器有的域名,而不能是"*"。
  res.header("Access-Control-Allow-Credentials", true);

  // 该字段可选,用来指定本次预检请求的有效期,单位为秒。
  // 当请求方法是PUT或DELETE等特殊方法或者Content-Type字段的类型是application/json时,服务器会提前发送一次请求进行验证
  // 下面的的设置只本次验证的有效时间,即在该时间段内服务端可以不用进行验证
  res.header("Access-Control-Max-Age", 300);

  /*
  CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:
    Cache-Control、
    Content-Language、
    Content-Type、
    Expires、
    Last-Modified、
    Pragma。
  */
  // 需要获取其他字段时,使用Access-Control-Expose-Headers,
  // getResponseHeader('myData')可以返回我们所需的值
  res.header("Access-Control-Expose-Headers", "myData");


  let {name, sex} = req.query;
  res.send({name, sex, _stamp: + new Date});
})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
IE和Firefox下javascript的兼容写法小结
Dec 10 Javascript
juqery 学习之三 选择器 层级 基本
Nov 25 Javascript
js用拖动滑块来控制图片大小的方法
Feb 27 Javascript
jQuery实现的手机发送验证码倒计时效果代码分享
Aug 24 Javascript
javascript加载xml 并解析各节点的值(实现方法)
Oct 12 Javascript
详解Vue中状态管理Vuex
May 11 Javascript
基于Vue实现图书管理功能
Oct 17 Javascript
使用vue-aplayer插件时出现的问题的解决
Mar 02 Javascript
详解React 的几种条件渲染以及选择
Oct 23 Javascript
详解微信小程序胶囊按钮返回|首页自定义导航栏功能
Jun 14 Javascript
微信小程序如何引用外部js,外部样式,公共页面模板
Jul 23 Javascript
微信小程序使用Vant Weapp组件库的方法步骤
Aug 01 Javascript
如何去除富文本中的html标签及vue、react、微信小程序中的过滤器
Nov 21 #Javascript
JSON生成Form表单的方法示例
Nov 21 #Javascript
apicloud拉起小程序并传递参数的方法示例
Nov 21 #Javascript
vue中组件的过渡动画及实现代码
Nov 21 #Javascript
详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序
Nov 21 #Javascript
Nuxt.js之自动路由原理的实现方法
Nov 21 #Javascript
nuxt.js中间件实现拦截权限判断的方法
Nov 21 #Javascript
You might like
用php+javascript实现二级级联菜单的制作
2008/05/06 PHP
PHP中mb_convert_encoding与iconv函数的深入解析
2013/06/21 PHP
PHP的Laravel框架结合MySQL与Redis数据库的使用部署
2016/03/21 PHP
php中的异常和错误浅析
2017/05/03 PHP
laravel model 两表联查示例
2019/10/24 PHP
JQuery的html(data)方法与&amp;lt;script&amp;gt;脚本块的解决方法
2010/03/09 Javascript
JavaScript设计模式之工厂模式和构造器模式
2015/02/11 Javascript
js图片模糊切换显示特效的方法
2015/02/17 Javascript
简介AngularJS中$http服务的用法
2016/02/06 Javascript
Vue入门之数据绑定(小结)
2018/01/08 Javascript
微信小程序异步API为Promise简化异步编程的操作方法
2018/08/14 Javascript
Vue 监听列表item渲染事件方法
2018/09/06 Javascript
使用Vue.js中的过滤器实现幂方求值的方法
2019/08/27 Javascript
深入了解JavaScript 防抖和节流
2019/09/12 Javascript
python分割列表(list)的方法示例
2017/05/07 Python
Python实现的排列组合计算操作示例
2017/10/13 Python
python PyTorch参数初始化和Finetune
2018/02/11 Python
Python+OpenCV感兴趣区域ROI提取方法
2019/01/10 Python
详解pytorch 0.4.0迁移指南
2019/06/16 Python
Python使用Pandas库实现MySQL数据库的读写
2019/07/06 Python
Python中利用LSTM模型进行时间序列预测分析的实现
2019/07/26 Python
解决Django加载静态资源失败的问题
2019/07/28 Python
python tkinter图形界面代码统计工具(更新)
2019/09/18 Python
什么是python的列表推导式
2020/05/26 Python
CSS3 rgb and rgba(透明色)的使用详解
2020/09/25 HTML / CSS
HTML5中form如何关闭自动完成功能的方法
2018/07/02 HTML / CSS
世界顶级足球门票网站:Live Football Tickets
2017/10/14 全球购物
俄罗斯品牌服装和鞋子在线商店:BRIONITY
2020/03/26 全球购物
《童趣》教学反思
2014/02/19 职场文书
模具专业自荐信
2014/05/29 职场文书
运动会方阵口号
2014/06/07 职场文书
个人融资协议书范本两则
2014/10/15 职场文书
2014年物流工作总结
2014/11/25 职场文书
保护校园环境倡议书
2015/04/28 职场文书
2015年数学教研组工作总结
2015/05/23 职场文书
解除处分决定书
2015/06/25 职场文书