美文网首页JavaScript
前端跨域请求方法整理

前端跨域请求方法整理

作者: Cause_XL | 来源:发表于2017-05-25 14:35 被阅读0次

前端跨域请求方法整理

什么是跨域请求

浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用。一般的,只要网站的 协议名protocol、 主机host、 端口号port 这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用。

我们利用 NodeJs 创建了两个服务器,分别监听 3000、 3001 端口(下面简称 服务器3000 与 服务器3001 ),由于端口号不一样,这两个服务器以及服务器上页面通信构成了跨域请求。

在服务器3000 上有如下的页面:

ajaximage.png

服务器3000 上的请求页面中包含如下 JavaScript 代码:

$(function () {
  $("#submit").click(function () {
    var data = {
      name: $("#name").val(),
      id: $("#id").val()
    };
    $.ajax({
      type: 'POST',
      data: data,
      url: 'http://localhost:3000/ajax/deal',
      dataType: 'json',
      cache: false,
      timeout: 5000,
      success: function (data) {
        console.log(data)
      },
      error: function (jqXHR, textStatus, errorThrown) {
        console.log('error ' + textStatus + ' ' + errorThrown);
      }
    });
  });
});

服务器3000 对应的处理函数为:

app.post('/ajax/deal', function (req, res) {
  console.log('server accept', req.body.name, req.body.id);
  var data = {
    name: req.body.name + '- server 3000 process',
    id: req.body.id + '- server 3000 process'
  };
  res.send(data);
  res.end();
})

请求页面返回结果:

ajaximage2.png

此处数据处理成功。

此时让 服务器3000 上的页面向 服务器 3001 发起请求:

$.ajax({
    ...
    url: 'http://localhost:3001/ajax/deal',
    ...
});

服务器3001 对应的处理函数与 服务器3000 类似:

app.post('/ajax/deal', function (req, res) {
  console.log('server accept', req.body.name, req.body.id);
  var data = {
    name: req.body.name + '- server 3001 process',
    id: req.body.id + '- server 3001 process'
  };
  res.send(data);
  res.end();
})

结果如下:

ajaximage3.png

结果由于端口号不同,发生了跨域请求。

需要注意的是,服务器 3001 控制台有输出:

server accept:  chiaki 3001

这说明跨域请求并非是浏览器限制了发起跨站请求,而是请求可以正常发起,到达服务器端,但是服务器返回的结果会被浏览器拦截。

利用 JSONP 实现跨域调用

JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题。其原理是根据 XmlHttpRequest 对象受到同源策略的影响,而 script 标签元素却不受同源策略影响,可以加载跨域服务器上的脚本,网页可以从其他来源动态产生 JSON 资料。用 JSONP 获取的不是 JSON 数据,而是可以直接运行的 JavaScript 语句。

1.使用 jQuery 集成的 $.ajax 实现 JSONP 跨域调用

依然是上面的例子,我们将 服务器 3000 上的请求页面的 JavaScript 代码改为:

// 回调函数
function jsonpCallback(data) {
  console.log('jsonpCallback:' + data.name)
}

$("#submit").click(function () {
  var data = {
    name: $("#name").val(),
    id: $("#id").val()
  };
  $.ajax({
    // type: 'POST',
    data: data,
    url: 'http://localhost:3000/ajax/deal',
    dataType: 'jsonp', //修改为jsonp
    cache: false,
    timeout: 5000,
    // jsonp 字段含义为服务器通过什么字段获取回调函数的名称
    jsonp: 'callback',
    // 声明本地回调函数的名称,jquery 默认随机生成一个函数名称
    jsonpCallback: 'jsonpCallback',
    success: function (data) {
      console.log("ajax success callback: " + data.name);
    },
    error: function (jqXHR, textStatus, errorThrown) {
      console.log('error ' + textStatus + ' ' + errorThrown);
    }
  });
});

服务器 3001 上对应的处理函数为:

app.post('/ajax/deal', function (req, res) {
  /* req.body.name -> req.query.name 
  jsonp实质为script的src链接: 
  /ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032 HTTP/1.1 */
  console.log('server accept', req.query.name, req.query.id);
  var data = "{" + "name:'" + req.query.name + " - server 3001 process'," + "id:'" + req.query.id + " - server 3001 process'" + "}"
  var callback = req.query.callback
  var jsonp = callback + '(' + data + ')'
  console.log(jsonp)
  res.send(jsonp)
  res.end()
})

这里一定要注意 data 中字符串拼接,不能直接将 JSON 格式的 data 直接传给回调函数,否则会发生编译错误: parsererror Error: jsonpCallback was not called。

其实脑海里应该有一个概念:利用 JSONP 格式返回的值一段要立即执行的 JavaScript 代码,所以不会像 ajax 的 XmlHttpRequest 那样可以监听不同事件对数据进行不同处理。

处理结果如下所示:

ajaximage6.png

2. 使用 script 标签原生实现 JSONP

由于实现的原理不同,由 JSONP 实现的跨域调用不是通过 XmlHttpRequset 对象,而是通过 script 标签,所以在实现原理上,JSONP 和 Ajax 已经一点关系都没有了。看上去形式相似只是由于 jQuery 对 JSONP 做了封装和转换。

比如在上面的例子中,我们假设要传输的数据 data 格式如下:

{
  name: "chiaki",
  id": "3001"
}

那么数据是如何传输的呢?HTTP 请求头的第一行如下:

GET /ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032 HTTP/1.1

可见,即使形式上是用 POST 传输一个 JSON 格式的数据,其实发送请求时还是转换成 GET 请求。

其实如果理解 JSONP 的原理的话就不难理解为什么只能使用 GET 请求方法了。由于是通过 script 标签进行请求,所以上述传输过程根本上是以下的形式:

<script src = 'http://localhost:3001/ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script>

这样从服务器返回的代码就可以直接在这个 script 标签中运行了。下面我们自己实现一个 JSONP:

服务器 3000请求页面的 JavaScript 代码中,只有回调函数 jsonpCallback:

function jsonpCallback(data) {
  console.log("jsonpCallback: "+data.name)
}

服务器 3000请求页面还包含一个 script 标签:

<script src='http://localhost:3001/jsonServerResponse?jsonp=jsonpCallback'></script>

服务器 3001上对应的处理函数:

app.post('/jsonServerResponse', function (req, res) {
  var cb = req.query.jsonp;
  console.log(cb);
  var data = 'var data = {' + 'name: $("#name").val() + " - server 3001 jsonp process",' + 'id: $("#id").val() + " - server 3001 jsonp process"' + '};'
  var debug = 'console.log(data);'
  var callback = '$("#submit").click(function() {' + data + cb + '(data);' + debug + '});'
  res.send(callback)
  res.end()
})

与上面一样,我们在所获取的参数后面加上 “ – server 3001 jsonp process” 代表服务器对数据的操作。从代码中我么可以看到,处理函数除了根据参数做相应的处理,更多的也是进行字符串的拼接。

最终的结果为:

ajaximage4.png

JSONP 总结

至此,我们了解了 JSONP 的原理以及实现方式,它帮我们实现前端跨域请求,但是在实践的过程中,我们还是可以发现它的不足:

  • 只能使用 GET 方法发起请求,这是由于 script 标签自身的限制决定的。
  • 不能很好的发现错误,并进行处理。与 Ajax 对比,由于不是通过 XmlHttpRequest 进行传输,所以不能注册 success、 error 等事件监听函数。

使用 CORS 实现跨域调用

Cross-Origin Resource Sharing(CORS)跨域资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。

CORS 的实现

服务器 3000 上的请求页面 JavaScript 不变,如下:

$(function() {
  $("#submit").click(function() {
    var data = {
      name: $("#name").val(),
      id: $("#id").val()
    };
    $.ajax({
      type: 'POST',
      data: data,
      url: 'http://localhost:3001/cors',
      dataType: 'json',
      cache: false,
      timeout: 5000,
      success: function(data) {
          console.log(data)
      },
      error: function(jqXHR, textStatus, errorThrown) {
          console.log('error ' + textStatus + ' ' + errorThrown);
      }
    });
  });
});

服务器 3001上对应的处理函数:

app.post('/cors', function(req, res) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
  res.header("X-Powered-By", ' 3.2.1')
  res.header("Content-Type", "application/json;charset=utf-8");
  var data = {
      name: req.body.name + ' - server 3001 cors process',
      id: req.body.id + ' - server 3001 cors process'
  }
  console.log(data)
  res.send(data)
  res.end()
})

在服务器中对返回信息的请求头进行了设置。

最终的结果为:

ajaximage5.png

CORS 与 JSONP 的对比

  • CORS 除了 GET 方法外,也支持其它的 HTTP 请求方法如 POST、 PUT 等。
  • CORS 可以使用 XmlHttpRequest 进行传输,所以它的错误处理方式比 JSONP 好。
  • JSONP 可以在不支持 CORS 的老旧浏览器上运作。

一些其它的跨域调用方式

window.name

window.postMessage()

相关文章

  • 前端跨域请求方法整理

    前端跨域请求方法整理 什么是跨域请求 浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScr...

  • 实现跨域请求的八种方式

    前端开发中我们经常会遇到跨域请求的情况,处理跨域请求方式很多,特整理如下: 浏览器的同源策略 提到跨域不能不先说一...

  • Javascript跨域整理

    在前端的JS请求中,跨域的问题经常存在,根据不同的实现原理,常见的跨域的方法如下: 一:前端的方式 1:在前端页面...

  • 前端请求

    node 简单跨域 前端简单请求

  • axios发送跨域请求需要注意的问题

    在实际项目中前端使用到vue,后端使用php进行开发。前端使用axios请求请求。 关于跨域 跨域的概念这些就不说...

  • spring boot + VUE跨域处理

    在使用 vue 做前端开发时,碰到 vue 请求接口出现跨域问题。解决的方法,就在后台添加一个跨域请求的过滤器,来...

  • 跨域请求(CORS)要点

    前端开发的童鞋,应该都有听过跨域请求,但这其中的细节可能还不清楚,比如: 什么是跨域请求? 为什么会存在跨域请求?...

  • express 实现跨域

    在前端向后端发起请求时会出现跨域无法请求的问题,所谓跨域是指前端的资源请求与所请求的资源本身的服务器在不同域或不同...

  • django跨域配置

    前言——跨域请求 前端对Cross-Origin Resource Sharing 问题(CORS,中文又称'跨域...

  • JavaScript - GET/POST及跨域方法

    xhr 原生方法请求 window fetch 方法 关于跨域 利用JSONP实现跨域调用 使用 CORS(跨域资...

网友评论

    本文标题:前端跨域请求方法整理

    本文链接:https://www.haomeiwen.com/subject/dtczxxtx.html