浅谈Ajax跨域

在web开发中,前端向后端发送请求,基本上都是用ajax的方式。如果我们前端页面的url和我们要提交的后端url存在跨域问题时,我们该如何解决呢? 下面将分别讨论几种解决方案。

1.1 CORS解决跨域

CORS是一套解决前后端跨域通信的解决方案,简单说是一种前后端用于允许跨域通信的一种约定机制。下图1 简单明了简述了CORS的概念。

图1 CORS通信示意图

只要浏览器和后端做好相关的对接和支持工作,CORS就能跑通。

目前除IE10以下的IE浏览器,其余主流浏览器均支持CORS。

服务器端,只需要设置特定的头就可以允许跨域通信:

//允许milo.qq.com的请求跨域
header("Access-Control-Allow-Origin:milo.qq.com");

//设置通配符,允许所有请求跨域
header("Access-Control-Allow-Origin:*");

有一点需要注意: 不建议后端配置Access-Control-Allow-Origin头为通配符*,因为为了安全起见,这种设置不可控。 建议后端以白名单的形式加header头,对于白名单内的请求,设置对应的跨域头,否则拒绝跨域。 可以参考:

//配置允许跨域请求的白名单origin
$allowed_origin= array(
    'http://a.qq.com',
    'http://b.qq.com',
    'http://www.qq.com'
);
//获取本次请求的origin
$origin=isset($_SERVER['HTTP_ORIGIN'])?$_SERVER['HTTP_ORIGIN']:'';

//判断是否白名单
if(in_array($origin,$allowed_origin)){
    //设置允许跨域头
    header("Access-Control-Allow-Origin:'.$origin);
}

1.2 跨域发送cookie

上面说到了CORS可以跨域,但是我们发现简单得设置了Access-Control-Allow-Origin头并不能把cookie带过去,cookie作为前后端通信中常用的数据载体经常用于校验凭证等数据传输,非常重要。 比如在a.qq.com的网站上,请求了一个c.qq.com/xxx.php 的接口,但是此接口需要从c.qq.com的域名下拿cookie中的登录态作为身份校验,这时发现cookie取不到。 下面简单介绍一下通过CORS实现跨域发送cookie。 设置withCredentials相关头 跨域发送cookie只需要前端带上withCredentials相关头,并且后端加上Access-Control-Allow-Credentials:true即可。 具体操作如下: [前端代码]

//当前位于a.qq.com中,向c.qq.com/xx.php接口发送请求
$.ajax({
    type:'GET',
    url:'http://c.qq.com/xx.php',
    xhrFields:{
        withCredentials:true
    },
    success:function(res){
        console.log(res);
    },
    fail:function(){

    }
})

[后端代码]

    //当前为c.qq.com/xx.php
    //设置为制定的origin,不能设置为*
    header('Access-Control-Allow-Origin:http://a.qq.com');
    //允许携带cookie
    header('Access-Control-Allow-Credentials:true');

[需要注意:] 跨域发送cookie,后端设置Access-Control-Allow-Origin头不能设置为通配符,否则浏览器将会拒绝跨域并报错。

1.3 jsonp解决跨域

jsonp本质上是script请求,是前端页面中用于外链script的一种请求方式。由于script标签有天然的跨域特性(拥有此特性的还用img标签等),而且其返回的内容为文本,且可以直接执行的特点。故通过将请求返回的内容封装成js脚本的形式,在前端直接执行的方式可以得到后端返回内容。 使用jsonp跨域请求后端可以这么做: [前端代码]

//以jquery调用为例
$.ajax({
    url:'http://c.qq.com/xx.php',
    dataType:'jsonp',//表示返回格式为jsonp
    type:'GET',
    success:function(res){
        console.log(res);
    },
    fail:function(){

    }
})

前端调用默认会发出一个类似: http://c.qq.com/xx.php?callback=xxxxxx 的请求到后端,后端拿到callback参数值,后会将其作为回调方法,直接返回一段用callback调用responseData的方法即可。

[后端代码]

$callbackName=$_GET['callback'] || 'callback';
$retData=array(
    "a" =>1,
    "b" =>2
);
echo $callbackName.'('.json_encode($retData).')';

[优点与缺点] 使用jsonp方式跨域的优点很明显,就是兼容性强,所有浏览器均支持。而且后端改造的成本也低。 缺点就是jsonp本质上是script请求,只能支持GET请求,对于大数据量和传输文件等都不支持,而且也无法拿到相关的返回头,状态码等数据。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏13blog.site

使用ajax方法实现form表单的提交

作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载。 写在前面的话 在使...

3225
来自专栏转载gongluck的CSDN博客

搭建 FTP 文件服务

安装并启动 FTP 服务 任务时间:5min ~ 10min 安装 VSFTPD 使用 apt-get 安装 vsftpd: sudo apt-get in...

8187
来自专栏张戈的专栏

Linux服务器的进程查看命令详解

Linux 服务器正常启动后,提供服务时会调用程序,占用进程。这时候我们如何查看系统中有哪些进程在被调用呢?我们可以通过以下命令来查看。 一、ps 命令 ps ...

2.6K9
来自专栏分布式系统和大数据处理

常用Git命令和操作(github)

git和github是不同的概念,git是版本控制工具,github是托管 Git项目的云端平台。

1304
来自专栏xingoo, 一个梦想做发明家的程序员

JSP Session管理

  本篇讲述JSP中session的相关知识和管理方法;   先说说cookie与session   在web中常用的两种用户信息管理方式:cookie 和 s...

2217
来自专栏JavaEdge

Spring Data JPA踩坑记:与Bootstrap Table的分页协作@PersistenceContext和@Resource的区别

注入一堆保存实体类状态的数据结构,针对实体类的不同状态(四种,managedh或detached等)可以做出不同的反应(merge,persist等等),其实就...

1101
来自专栏栗霖积跬步之旅

异常:org.springframework.http.converter.HttpMessageNotReadableException

spring(springboot、springmvc)出现标题的异常一般是由于controller的入参失败引起的。

1554
来自专栏程序员叨叨叨

一招搞定Windows无法安装到GPT分区形式磁盘疑难

今天给堂弟的电脑重装系统时,遇到了以往USB安装系统经常出现的问题,“Windows无法安装到这个磁盘。选中的磁盘采用GPT分区形式”。之前在CSDN的博客上有...

602
来自专栏三木的博客

使用mock来编译和管理RPM软件包

buildroot 在打包时用到的spec文件中包含一些tag,这些对大小写不敏感的tag用冒号来定义。BuildRoot就是其中的一个tag。例如,在libv...

2279
来自专栏LanceToBigData

MongoDB(一)环境搭建与初始配置

前言   最近的项目中需要用到MongoDB,所这段时间需要学习知道怎么去使用这个数据库。   这里我先简单的介绍一下什么是MongoDB,后面还会详细的介绍:...

4845

扫码关注云+社区