利用jsonp与代理服务器方案解决跨域问题

前言

本文将从实践角度介绍如何使用jsonp和代理服务器方案解决跨域问题,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

浏览器为了保护用户安全,引入了同源策略,即一个服务器页面无法访问另一个协议、域名、端口不同的服务器数据。当页面需要跨服务器访问另一个服务器的数据时,即产生跨域行为。以豆瓣的公开API(https://api.douban.com/v2/book/1220562)为例,当前我的服务器处于http://127.0.0.1:5000下,豆瓣的服务器很显然跟我的服务器不同源,服务器中的一个页面通过AJAX请求该接口时,浏览器会发出如下警告,并且页面获取数据失败:

在实际开发中,如果遇到这样的跨域问题,可以通过以下办法获得跨域的数据:

  • 异源服务器的响应头部设置Access-Control-Allow-Origin允许跨域行为
  • JSONP
  • 设置自己的代理服务器转发异源的数据

对于第一种设置Access-Control-Allow-Origin的方法,如果在Python Flask搭建的服务器下,可以设置一个简单的修饰器:

from functools import wraps
from flask import make_response

def allow_cross_domain(fun):
 @wraps(fun)
 def wrapper_fun(*args, **kwargs):
  rst = make_response(fun(*args, **kwargs))
  rst.headers['Access-Control-Allow-Origin'] = '*'
  rst.headers['Access-Control-Allow-Methods'] = 'PUT,GET,POST,DELETE'
  allow_headers = "Referer,Accept,Origin,User-Agent"
  rst.headers['Access-Control-Allow-Headers'] = allow_headers
  return rst
 return wrapper_fun

@app.route('/hosts/')
@allow_cross_domain
def domains():
 pass

如果在express搭建的服务器中,类似的可以加入这样一个中间件:

//allow custom header and CORS
app.all('*',function (req, res, next) {
 res.header('Access-Control-Allow-Origin', '*');
 res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
 res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');

 if (req.method == 'OPTIONS') {
  res.send(200); /让options请求快速返回/
 }
 else {
  next();
 }
});

但是设置Access-Control-Allow-Origin的方法有个致命的缺陷,就是只能在提供接口的服务器上进行添加,如果该服务器不是自己开发的话(例如上面提到的豆瓣公开API),这个方法基本可以忽略,那么留给我们自由发挥的方法就只有JSONP和代理服务器了。网上有关于很多JSONP和代理服务器解决跨域的介绍,但都缺少具体的实践案例,本文将通过具体的实际案例来了解这两个跨域方式的具体实现。

撰写本文时,我手头上可以直接拿来用的后端方案为Flash搭建的RESTful服务器,前端方案为Vue 1.0 + vue-resource进行Ajax,故下面所述具体的实践操作都在这两个环境上进行,如果你的开发环境和这个有差异也没关系,本文将有最少的逻辑代码来展示跨域的实现原理,其他方案可触类旁通。

JSONP

浏览器的同源策略限制的跨域的Ajax请求资源,但是script标签中的资源却可以跨域获取,很常见的就是我们通过script标签引用其他服务器的js:

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>

JSONP的原理就是利用浏览器对script标签没有同源限制,动态创建script标签,把需要请求的API放在script标签的src不受同源策略限制的特性来获得数据。

JSONP由回调函数(callback)和返回的数据(response)两部分组成。回调函数(callback)是当script创建src引入资源结束时调用,返回的数据(response)作为回调函数的第一个参数传入,在回调函数里即可保存获得的不同源数据。具体来看例子,我们在页面加载的时候获取数据,请求https://api.douban.com/v2/book/1220562:

// 在vue中需要将回调函数作为一个全局函数,否则在vue的生命周期中将获取不到这个回调函数
var d = null;
function handleResponse(response){
 console.log(response);
 d = response;
}

compiled: function() {
 var self = this;
 // jsonp
 var script = document.createElement("script"); // 动态创建标签
 script.src = "https://api.douban.com/v2/book/1220562?callback=handleResponse"; // 创建的src就是请求的API,同时需要给这个src加上一个callback的query参数,参数名字就是你的回调函数名字
 document.body.appendChild(script, document.body.firstChild); // 插入新创建的script标签,这里类似Ajax发起请求

 // 轮询资源获取是否结束
 var timer = setInterval(function () {
 if (d) {
  console.log('pending')
  clearInterval(timer);
  self.data = d; // 将获取的数据赋值给数据model中
 }
 }, 500);
}

此时刷新页面,浏览器不再发出Access-Control-Allow-Origin的跨域错误,输出通过script获取到的数据:

JSONP的缺点

JSONP的缺点主要源自他的script引用资源方式,JSONP的缺点如下:

  • JSONP是通过script标签获取资源的,也就是说JSONP注定只能用GET的方式访问资源,GET以外的请求无法做到;
  • JSONP是通过src引用不同源的代码,如果其他域的代码存在恶意代码,那么这将造成严重的网络安全,如果需要跨域的服务器不足以信任,那么必须放弃JSONP;
  • 要确定JSONP请求是否成功,需要启动一个计时器监测数据变动。

针对以上JSONP的缺点,如果需要进行改进,就需要使用代理服务器了。

代理服务器

代理服务器解决跨域的思路是利用代理服务器对浏览器页面的请求进行转发,因为同源策略的限制只存在在浏览器中,到了服务器端就没有这个限制了,常用的代理服务器方案有使用反向代理服务器以及服务器内转发,使用反向代理服务器的例子是Nginx的反向代理,通过修改Nginx的配置文件,将指定的不同源域名代理到当前服务器上,浏览器就可以正常访问不同源的资源了。还有个方案是不依赖反向代理服务器,在server端对不同源的API进行转发,本文主要对这种方法进行介绍。

首先代理服务器需要知道浏览器页面需要请求的API,因此,页面需要把API当做参数传递给代理服务器,形如:/proxy/:api,api参数是完整的API链接,如之前提到的豆瓣公共API:https://api.douban.com/v2/book/1220562。server端对API进行转发,在Python中可以使用requests发起HTTP请求,nodejs可以使用request,server端获得响应后将响应的结果返回给浏览器,具体的实现也很简单,以Flask为例:

@app.route('/proxy/<path:url>', methods=['GET'])
def getTasks(url):
 r = requests.get(url) ## 请求转发
 conver_r = eval(bytes.decode(r.content)) ##进行一些类型转化

 return json.dumps(conver_r), 200

在浏览器端发起请求的具体代码为:

self.$http.get('/proxy/https://api.douban.com/v2/book/1220562').then(function(res) {
 self.data = JSON.parse(res.data)
});

此时打开浏览器控制台,可以看到server转发的请求结果,跨域成功。

与JSONP相比代理服务器的优点

相比JSONP,使用代理服务器转发不同源API的优点如下:

  • 资源获取是通过server端进行,可以根据需要转发的API选择使用GET以外的HTTP方法进行资源请求;
  • 请求的资源需要经过server端转发到浏览器端,server端可以对资源进行处理,因此可以避免一些直接的恶意代码,比JSONP更安全;
  • 浏览器页面正常使用Ajax请求数据,通过回调可以得知请求是否结束,不再需要使用计时器监测。

代理服务器的缺点

使用代理服务器的缺点是对不同源资源的转发请求,如果同时多个用户进行跨域请求,因为服务器内部需要进行额外的HTTP请求,那么服务器端的处理压力降会变大,从而导致阻塞等一系列性能问题,如需更好的方案,还是得使用Nginx等反向代理服务器进行端口代理处理。

总结

本文从实践的角度介绍了JSONP和代理服务器的处理跨域的做法,并对比了两种方案的优缺点,如果是一些安全要求性不高的场景,可以直接使用JSONP进行跨域请求,如果是需要额外的HTTP请求并且安全性要求较高,跨域请求还是从server端发起为佳,当然还有其他跨域方案,需要读者根据自身的能力和判断去舍取。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Jsonp post 跨域方案

    近期在项目中遇到这样一问题,关于jsonp跨域问题,get传值是可以的,但post传值死活不行啊,于是网上看了一大堆关于这方面的资料,最终问题得以解决,今天抽空与大家分享下. 说明: http://www.t1.com/index.php 服务端URL 当然这是我本地配置的,需要改为自己对应的地址. 客户端代码: <script> $(function(){ var url = 'http://www.t1.com/index.php'; $.ajax({ type: 'post', url:

  • AJAX跨域请求之JSONP获取JSON数据

    Asynchronous JavaScript and XML (Ajax ) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术.Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索.使用 XMLHttpRequest 函数获取数据,它是一种 API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器.Ajax 也是许多 mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序. 不过,由于受到浏览器的限制,该

  • JSONP 跨域访问代理API-yahooapis实现代码

    你是否遇到了想利用AJAX访问一些公网API,但是你又不想建立自己的代理服务,因为有时我根本就没打算涉及服务端任何代码,但是讨厌的浏览器的同源策略,阻止了我们的ajax调用. 比如我想访问一个天气的restfull api,如果我直接去GET: 复制代码 代码如下: $.get("http://m.weather.com.cn/data/101010100.html");  看见这问题相信大家都不会陌生,也会很自然的得到解决方案,但是我这里真的不想touch任何服务端代码,用jsonp

  • 用jQuery与JSONP轻松解决跨域访问的问题

    时间过得好快,又被拉回js战场时, 跨域问题这个伤疤又开疼了. 好在,有jquery帮忙,跨域问题似乎没那么难缠了.这次也借此机会对跨域问题来给刨根问底,结合实际的开发项目,查阅了相关资料,算是解决了跨域问题..有必要记下来备忘. 跨域的安全限制都是指浏览器端来说的.服务器端是不存在跨域安全限制的,所以通过本机服务器端通过类似httpclient方式完成"跨域访问"的工作,然后在浏览器端用AJAX获取本机服务器端"跨域访问"对应的url.来间接完成跨域访问也是可以的

  • 使用jsonp完美解决跨域问题

    调用web接口,get请求,发现提示:No 'Access-Control-Allow-Origin' header is present on the requested resource. 这个和安全机制有关,默认不允许跨域调用 处理手段:使用jsonp格式, ajax请求参数dataType:'JSONP'. 复制代码 代码如下: $.ajax({         url: "http://.......",         type: 'GET',         dataTy

  • Jsonp 跨域的原理以及Jquery的解决方案

    原理:JSONP即JSON with Padding.由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名.协议.端口)的资源.如果要进行跨域请求,我们可以通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象.这种跨域的通讯方式称为JSONP. 个人理解: 就是在客户端动态注册一个函数function a(data),然后将函数名传到服务器,服务器返回一个a({/*json*/})到客户端

  • JSONP跨域的原理解析及其实现介绍

    JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进行多iframe或多窗口编程.以及Ajax编程时显得尤为重要.根据这个策略,在baidu.com下的页面中包含的JavaScript代码,

  • 利用jsonp与代理服务器方案解决跨域问题

    前言 本文将从实践角度介绍如何使用jsonp和代理服务器方案解决跨域问题,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 浏览器为了保护用户安全,引入了同源策略,即一个服务器页面无法访问另一个协议.域名.端口不同的服务器数据.当页面需要跨服务器访问另一个服务器的数据时,即产生跨域行为.以豆瓣的公开API(https://api.douban.com/v2/book/1220562)为例,当前我的服务器处于http://127.0.0.1:5000下,豆瓣的服务器很显然跟我的服务

  • springboot中如何通过cors协议解决跨域问题

    1.对于前后端分离的项目来说,如果前端项目与后端项目部署在两个不同的域下,那么势必会引起跨域问题的出现. 针对跨域问题,我们可能第一个想到的解决方案就是jsonp,并且以前处理跨域问题我基本也是这么处理. 但是jsonp方式也同样有不足,不管是对于前端还是后端来说,写法与我们平常的ajax写法不同,同样后端也需要作出相应的更改.并且,jsonp方式只能通过get请求方式来传递参数,当然也还有其它的不足之处,针对于此,我并没有急着使用jsonp的方式来解决跨域问题,去网上找寻其它方式,也就是本文主

  • js前端解决跨域的八种实现方案

    由于同源策略的限制,满足同源的脚本才可以获取资源.虽然这样有助于保障网络安全,但另一方面也限制了资源的使用. 那么如何实现跨域呢,以下是实现跨域的一些方法. 一.jsonp跨域 原理:script标签引入js文件不受跨域影响.不仅如此,带src属性的标签都不受同源策略的影响. 正是基于这个特性,我们通过script标签的src属性加载资源,数据放在src属性指向的服务器上,使用json格式. 由于我们无法判断script的src的加载状态,并不知道数据有没有获取完成,所以事先会定义好处理函数.服

  • js前端解决跨域问题的8种方案(最新最全)

    1.同源策略如下: URL 说明 是否允许通信 http://www.a.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

  • 快速解决跨域请求问题:jsonp和CORS

    网上各种跨域教程,各种实践,各种问答,除了简单的 jsonp 以外,很多说 CORS 的都是行不通的,老是缺那么一两个关键的配置.本文只想解决问题,所有的代码经过亲自实践. 本文解决跨域中的 get.post.data.cookie 等这些问题. 本文只会说 get 请求和 post 请求,读者请把 post 请求理解成除 get 请求外的所有其他请求方式. JSONP JSONP是利用浏览器对script的资源引用没有同源限制,通过动态插入一个script标签,当资源加载到页面后会立即执行的原

  • 如何利用PHP 快速解决跨域问题

    目录 跨域介绍 跨域介绍 跨域解决方案 跨域介绍 浏览器拥有同源策略限制确保安全,同源策略会阻止一个域的Javascript脚本和另外一个域的内容进行交互. 当一个请求url的协议.域名(包括多级域名).端口三者之间任意一个与当前页面url不同即为跨域. 跨域介绍 1)无法读取非同源网页的 Cookie.LocalStorage 和 IndexedDB 2)无法接触非同源网页的 DOM 节点 3)无法向非同源地址发送 AJAX 请求 跨域解决方案 1)JSONP(只支持GET请求) Javasc

  • 原生js的ajax和解决跨域的jsonp(实例讲解)

    最近慢慢感觉,学再多框架,库,都不如老老实实先把基础弄扎实了. 不说废话,先上一个用ajax请求下本地的一个.txt文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script> window.onload =function(){ var oBtn = d

  • 利用nginx解决跨域问题的方法(以flask为例)

    前言 我们单位的架构是在api和js之间架构一个中间层(python编写),以实现后端渲染,登录状态判定,跨域转发api等功能.但是这样一个中间会使前端工程师的工作量乘上两倍,原本js可以直接ajax请求api,但是我们不得不ajax请求中间层,中间层再请求api. 如图: 为了少敲代码,提高工作效率,我们当然希望将python中间层砍掉,但是如何解决以下三个问题,成为关键: 后端渲染 登录状态判定 跨域转发api 关于1,2我会在另外两篇博客中详细叙述,这篇文章主要解决3,也就是跨域问题.解决

  • 说说如何利用 Node.js 代理解决跨域问题

    前后端分离,经常会出现跨域访问被限制的问题. 跨域访问限制是服务端出于安全考虑的限制行为.即只有同域或者指定域的请求,才能访问.这样还可以防止图片被盗链.服务端(比如 Node.js)可以通过代理,来解决这一问题. 1 安装 request 库 npm install request --save-dev 2 配置 我们以知乎日报为例,配置两个代理.一个代理内容,另一个代理图片. 在项目根目录,配置 proxy.js : //代理 const http = require('http'); co

  • 关于后端如何解决跨域的问题说明

    目录 什么是跨域请求 什么是同源策略 同源策略限制内容有 那什么又是同源? 跨域解决方案 1.jsonp 2.cors 3.@CrossOrigin注解 4.使用SpringCloud网关 5.Node中间件代理(两次跨域) 6.nginx反向代理 总结 对于跨域,相信同学们都有所了解.前端的跨域的若干种方式,大家也都知道,什么 JSONP,iframe+domain 等等.但是我们今天的主题,不是前端跨域,而是后端跨域. 一旦提及到跨域,就会想到同源策略,那我们就先来回顾跨域和同源策略. 什么

随机推荐