热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

接口开发跨域访问解决方案简单汇总

1引言这是16年写的一篇小调查,现在贴到博客中。因为当时时间有限、水平有限,所以内容较浅,而且还有很多不当之处。还有就是当时参考的那些文章现在也记不得了,深感抱歉!1.1编写目的编

1 引言

这是16年写的一篇小调查,现在贴到博客中。
因为当时时间有限、水平有限,所以内容较浅,而且还有很多不当之处。
还有就是当时参考的那些文章现在也记不得了,深感抱歉!

1.1 编写目的

编写接口开发跨域访问解决方案汇总的主要目的是,归纳整理目前可供选用的解决接口跨域访问的解决方案。
接口调用开发模式需要考虑一个重要的问题,即跨域访问问题。
跨域访问有两个方向的解决策略:

  1. 将前端页面和接口部署在统一域名下,则不存在跨域访问的问题;
  2. 前端页面和接口部署在不同的域名下,通过技术解决跨域访问的技术难点。本文主要描述的是前端页面和接口部署在不同的域名下,可用选择的跨域解决方案。

1.2 概念简介

同源策略:阻止从一个源加载的文档或脚本获取或设置另一个源上加载的文档的属性。这个策略可以追溯至Netscape Navigator 2.0。
简单地说就是要求动态内容(例如,Javascript或者Vbscript)只能阅读与之同源的那些HTTP应答和COOKIEs,而不能阅读来自不同源的内容。为了形象地进行展示,下表罗列了几类URL的同源检测结果。

序号URL结果说明
1http://www.demo.cn/demo/other.html–原地址
2http://www.demo.cn/demo/other2.html成功同一域名同一文件夹下允许
3http://www.demo.cn/demo2/other.html成功同一域名不同文件夹下允许
4https://www.demo.cn/demo/other.html失败协议不同不允许
5http://www.demo.cn:8080/demo/ot.html失败端口号不同不允许
6http://192.168.7.38/demo/other.html失败域名对应ip和域名之间不允许
7http://script.demo.cn/demo/oer.html失败主域名相同,子域名不同,不允许
8http://demo.cn/demo/other.html失败同一域名,不同二级域名,不允许
9http://www.api.cn/demo/other.html失败不同域名之间不允许

由上表总结:在协议、域名相同时,不涉及跨域访问;其他情况下,都涉及跨域访问。

2 解决方案

解决跨域访问可用的解决方案有多种,本为整理的有五种:JSONP、CORS、FLASH、PROXY、IFRAME。下面分别从原理、优点、缺点、开发复杂度和示例五个方面对五种解决方案进行描述。

2.1 JSONP

2.1.1 原理

在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,但img、iframe、script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。
JSONP就是通过script节点src调用跨域的请求。当我们通过JSONP模式请求跨域资源时,服务器返回给客户端一段Javascript代码,这段Javascript代码自动调用客户端回调函数。

2.1.2 优点

使用方便,同时支持大多部分浏览器版本。

2.1.3 缺点

只支持GET提交方式,不支持其他POST提交。

2.1.4 开发复杂度

与同源开发相比,只需前端页面和后台接口修改少量代码即可。

2.1.5 示例

前台页面:

$.ajax({
url:'http://192.168.7.38:8080/telapi/LoginAction.do?method=login',
dataType:"jsonp",
data:{username:'zhangsan',password:'0'},
jsonpCallback:"success_jsonp",
success:function(data){
$("#te").val(data);
}
});

后台接口:

response.setContentType("text/html;charset=utf-8");
PrintWriter pw = response.getWriter();
pw.write("success_jsonp(" + result + ")");
pw.flush();
pw.close();

2.2 CORS

2.2.1 原理

Cross-Origin Resource Sharing,W3C制定的跨域资源分享标准。post前会产生一次options嗅探(称之为preflight,但简单请求不会出现)来确认有否跨域请求的权限;客户端post时会带上Origin头指示来源网站,服务端响应时需带上Access-Control-Allow-Origin头与Origin头的值匹配,以示许可。

2.2.2 优点

W3C标准方案,实现简单。

2.2.3 缺点

支持的浏览器有限,IE需要较高版本,具体浏览器支持情况见下图。
《接口开发-跨域访问-解决方案简单汇总》

2.2.4 开发复杂度

与同源开发相比,只需后台接口增加少量代码。

2.2.5 示例

前台页面:

//前端页面使用普通的Ajax提交方式,跟同源访问一样,无需更改。

后台接口:

//这句代码中*代码,服务器允许任何人访问。当然可以设置规定访问的域名。
//比如只允许http://localhost:8080/crcp这个域下的访问。则把*代替成这个域名即可。
response.setHeader("Access-Control-Allow-Origin", "*");

2.3 FLASH

2.3.1 原理

利用的swf格式文件跨域post提交数据,需要部署crossdomain.xml。Javascript 将数据提交给本域的 Flash,通过 Flash 中转去访问其他域的接口,条件只需要其他域的根目录下有一个crossdomain.xml文件,文件中设置允许所有域名或允许本域访问即可。

2.3.2 优点

ADOBE标准方案,相对CORS兼容性佳,相对invisible iframe响应数据量较大的时候优势明显。

2.3.3 缺点

依赖flash(要求flash9及以上)。

2.3.4 开发复杂度

与同源开发相比,前端页面需引入swf,并需要在form中用自定义post方法调用接口。后台接口需做少量代码修改。

2.3.5 示例

此示例参考“张宴”的文章:http://blog.s135.com/ajaxcdr/。
在“Cross-domain AJAX using Flash”的基础上,增加了对表单进行智能处理的功能,封装了一个Javascript包:AJAXCDR。通过 AJAXCDR,即可轻松地解决 Javascript 和 AJAX 跨域 HTTP POST/GET 表单请求,支持IE、Firefox、谷歌Chrome等多种浏览器。
AJAXCDR 拥有两个文件:ajaxcdr.js 和 ajaxcdr.swf,AJAXCDR 拥有一个 Javascript 函数 AjaxCrossDomainRequest() 和一个全局变量 AjaxCrossDomainResponse。
AJAXCDR 函数说明:
1、Javascript函数:
AjaxCrossDomainRequest(URL, Method, FormName, CallBack):
参数说明:
URL:需要访问的URL地址,相当于表单的action=的值。
Method:方法,本函数支持POST和GET方法,相当于表单的method=的值。
FormName:表单名称,相当于表单的name=的值。
CallBack:回调函数,请求完成后,回调用户的一个函数,用户可以在该函数内对返回值进行处理。

AjaxCrossDomainResponse:
当用户调用AjaxCrossDomainRequest()函数完成 HTTP POST/GET 请求后,该函数会把服务器端返回的数据写入到AjaxCrossDomainResponse变量中,您可以通过AjaxCrossDomainResponse变量获取返回值。
前台页面:

<form name="cross_domain_demo">
<input name="title" type="text" value="测试数据">
form>
<a href="Javascript:AjaxCrossDomainRequest('http://api.bz/ajaxcdr/echo.php', 'POST', 'cross_domain_demo', 'mycallback()');">提交a>
<script type="text/Javascript"> function mycallback(){ alert(AjaxCrossDomainResponse); } script>
<script type="text/Javascript" src="/demo/ajaxcdr/ajaxcdr.js">script>

后台接口:

header("Cache-Control: no-cache, must-revalidate");
var_export($_REQUEST);
?>

2.4 PROXY

2.4.1 原理

当前域实现一个代理,所有向外部域名发送的请求都经由该代理中转。
举例说明(以asp.net为例):页面a.aspx在域domain1.com中,页面b.aspx在域domain2.com中,a.aspx通过ajax请求b.aspx数据则为跨域。在域domain1.com放置代理页面temp.aspx,那么a.aspx访问temp.aspx就是同一域了。而temp.aspx再去访问b.aspx返回数据给a.aspx,这样问题是不是已经解决了呢,temp.aspx访问b.aspx不也是跨域访问吗?这就是重点:a.aspx访问temp.aspx发送请求时已通过Form身份验证了,请求已到达服务器端,而temp.aspx在服务器端访问获取b.aspx的数据则不存在Form身份验证,所以代理页面temp.aspx代码应该运行在服务器端,也就是将获取数据的代码写到temp.cs当中即可。

2.4.2 优点

对同源开发的代码修改较少。

2.4.3 缺点

需配置代理,数据中转低效。

2.4.4 开发复杂度

与同源开发相比,前端页面需少量代码修改,后台接口需添加并配置代理。

2.4.5 示例

用Nginx反向代理实现跨域,只需要修改Nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。
我们只需要配置Nginx,在一个服务器上配置多个前缀来转发http/https请求到多个真实的服务器即可。这样,这个服务器上所有url都是相同的域名、协议和端口。因此,对于浏览器来说,这些url都是同源的,没有跨域限制。而实际上,这些url实际上由物理服务器提供服务。这些服务器内的Javascript可以跨域调用所有这些服务器上的url。
下面,给出一个Nginx支持跨域的例子,进行具体说明。
如,我们有两个pythonflask开发的项目:testFlask1和testFlask2。
testFlask2项目上的Javascript脚本要通过ajax方式调用testFlask1的一个url,获取一些数据。
正常情况下部署,就会有跨域问题,浏览器拒绝执行如下这样的调用。

$("button").click(function () {
$.get("127.0.0.1:8081/partners/json", function (result) {
$("div").html(result);
});

下面把testFlask2项目的javascrip文件修改一下。这样访问同源的url,就不会有跨域问题。

$("button").click(function () {
$.get("partners/json", function (result) {
$("div").html(result);
});

但是,我们testFlask2项目实际上没有partners/json这样的url,那怎么处理呢?
我们这样编写Nginx的配置文件:

server{
listen8000;
location/ {
includeuwsgi_params;
uwsgi_passunix:/tmp/testFlask2.sock;
}
location/partners {
rewrite^.+partners/?(.*)$ /$1 break;
includeuwsgi_params;
uwsgi_passunix:/tmp/testFlask1.sock;
}
}

我们把testFlask2项目部署在8080端口的根目录下。把提供web服务的testFlask1项目部署在/partners目录下。但我们的testFlask1项目并不能处理/partners/json这样的url请求。那怎么办呢?通过rewrite^.+partners/?(.*)$ /$1 break; 这一条命令,Nginx可以把收到的/partners/*请求全部转为/*请求后再转发给背后的真实web服务器。这样,RESTFUL的ajax客户端程序,只需要给出特定前缀的url就可以调用任意服务器提供的RESTFUL接口了。
甚至,通过Nginx的反向代理,我们还能调用其他公司开发的网站提供的RESTFUL接口。如:

location/sohu {
rewrite^.+sohu/?(.*)$ /$1 break;
includeuwsgi_params;
proxy_passhttp://www.sohu.com/;
}

我们就把sohu网站整个搬到我们的8080:/sohu/目录下了,我们的Javascript就可以尽情调用其RESTFUL服务了。顺便说一下,rewrite^.+sohu/?(.*)$ /$1 break; 这句命令中,$1表示(.*)这个部分。第一对()内的参数是$1,第二对()内的参数就是$2,以此类推。
Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。Nginx作为反向代理服务器,就是把http请求转发到另一个或者一些服务器上。
通过把本地一个url前缀映射到要跨域访问的web服务器上,就可以实现跨域访问。
对于浏览器来说,访问的就是同源服务器上的一个url。而Nginx通过检测url前缀,把http请求转发到后面真实的物理服务器。并通过rewrite命令把前缀再去掉。这样真实的服务器就可以正确处理请求,并且并不知道这个请求是来自代理服务器的。
简单说,Nginx服务器欺骗了浏览器,让它认为这是同源调用,从而解决了浏览器的跨域问题。又通过重写url,欺骗了真实的服务器,让它以为这个http请求是直接来自与用户浏览器的。
这样,为了解决跨域问题,只需要动一下Nginx配置文件即可。

2.5 IFRAME

2.5.1 原理

通过js动态生成不可见表单和iframe,将表单的target设为iframe的name以此通过iframe做post提交。提交后由于跨域,无法直接读取响应内容。一般的做法是,iframe内通过js改变自身location的fragment,外部则监听iframe的onload事件,读取fragment的内容。有现成的跨域iframe通信类库,如jQuery PostMessage Plugin。

2.5.2 优点

兼容性佳,facebook,google,新浪已/曾采用

2.5.3 缺点

依赖hack实现,响应数据量大时需要切片、多次设置fragment并轮询,响应频繁时可能失效。据说Firefox等可能不支持读取另一个iFrame的内容。

2.5.4 开发复杂度

2.5.5 示例

1.创建一个iframe

try{
// IE6, IE7
iframe = document.createElement('');
} catch(e) {
iframe = document.createElement('iframe');
iframe.name = {iframeName};
}
iframe.style.display = 'none';
document.body.appendChild(iframe);

2.监听iframe的onload事件

if(iframe.readyState){
iframe.Onreadystatechange= function(){
if (iframe.readyState && iframe.readyState=='complete'){
callbackFunction.apply(this);
}
}.bind(this);
} else {
iframe.Onload= callbackFunction.bind(this);
}

3.创建表单,并自动提交

form = document.createElement('form');
form.action = {url};
form.target = {iframeName}; // important!!
form.method = 'post';
input = document.createElement('input');
input.name = {inputName};
input.value = {inputValue};
input.type = 'hidden';
form.appendChild(input);
document.body.appendChild(form);
form.submit();
/** 备注 1. form.target 必须要与iframe.name相同;当表单提交后,页面会target到隐藏的iframe,并且不刷新页面,实现跨域。 2. form表单必须要append到页面上,否则不能使用js提交(chrome除外)。 **/

4.callbackFunction 获取iframe的内容

iframeCOntent= iframe.contentDocument? iframe.contentDocument: iframe.contentWindow.document;

5.php的返回值


<html>
<body>
<script>document.domain="xxxx.com";script>
<script type="text/json-result">'.json_encode($result).'script>
body>
html>
/** 备注 **/
1. 在IE下,必须要是完整的html页面才能找到document对象
2. 返回的结果,要加入document.domain,确保可以跨域访问
3. 返回的结果放到script标签中,标签可以采用特殊的type标注,以便在js中获取结果
4. js中获得的json是string,可以通过evalJSON()将其转为json数据
/** 备注 **/

3 总结

通过章节2,可以详细地了解五种解决方案的优劣之处,为了方便对这些解决方案有直观的对比,下表2列出了五种解决方案的优劣对比结果。

序号解决方案GETPOST版本支持易用性稳定性效率依赖
1JSONP×良好简单良好良好&#8211;
2CORS一般简单良好良好&#8211;
3FLASH良好一般良好良好FLASH9
4PROXY良好一般良好一般代理支持
5IFRAME良好一般一般良好&#8211;

推荐阅读
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • javascript二叉树基本功能实现
    都是常用的功能。删除是最复杂的。。test ... [详细]
  • matlab串口编程由于项目需要,用matlab做了一个串口通信工具,也碰到不少坑。这里总结一下。读取串口数据matlab支持串口通信,因此直接调用串口的结构体serial就可以, ... [详细]
  • 变动|时限_即时通讯开发技术分享HTTP长连接长轮询
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了即时通讯开发技术分享HTTP长连接长轮询相关的知识,希望对你有一定的参考价值。在 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 本文介绍了如何使用jQuery和AJAX来实现动态更新两个div的方法。通过调用PHP文件并返回JSON字符串,可以将不同的文本分别插入到两个div中,从而实现页面的动态更新。 ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
  • 由于同源策略的限制,满足同源的脚本才可以获取资源。虽然这样有助于保障网络安全,但另一方面也限制了资源的使用。那么如何实现跨域呢,以下是实现跨域的一些方法。 ... [详细]
author-avatar
人在做天在看1212_906
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有