基于thinkphp的ajax跨域解决方案

本文详细介绍了如何在ThinkPHP框架中解决跨域问题,通过自定义控制器类实现全局跨域设置,同时对框架内部判断机制进行了优化以确保AJAX请求正确处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

周末在家仔细研究了一下ajax跨域的问题,虽然可以用jsonp但jsonp只能用于GET请求,所以还是深入了一下。

CORS的具体内容大家可网上搜一下,这里主要是设置一个名为“Access-Control-Expose-Headers”的报头对响应报头进行授权。PHP中使用header("Access-Control-Allow-Origin:*");就可以了。

thinkphp中 控制器返回之前加一行header("Access-Control-Allow-Origin:*");也能成功,但是如果每个控制器函数都写这么一句就太费事了。所以创建了一个AjaxController类继承Controller类,并在构造函数中添加了

class AjaxController extends Controller {

   public function __construct(){
       parent::__construct();//调用父类的方法,因为这里重写了父类的方法
       //用于解决前台ajax跨域请求
     header("Access-Control-Allow-Origin:*");
       //header("Access-Control-Allow-Origin:http://111.com");
   }
}

其他控制器全部继承此类

class IndexController extends AjaxController {

 测试成功。但又发现另一个问题

thinkphp文档里提到的success和error方法会自动判断当前请求是否属于Ajax请求,如果属于Ajax请求则会调用ajaxReturn方法返回信息。 ajax方式下面,success和error方法会封装下面的数据返回:

经过一翻排查发现success并没有以ajax方式返回。这里有两个解决方法,一是指定success的第三个参数为true(error同理)。

但这样就失去了灵活性,本着一挖到底的原则最后找到了\ThinkPHP\Library\Think\Controller.class.php中的

private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) {
   if(true === $ajax || IS_AJAX )

 这里用于判断是否为ajax提交过来的。IS_AJAX在\ThinkPHP\Library\Think\App.class.php中,内容为

define('IS_AJAX',       ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false);

看来IS_AJAX并不能很好的反映是否为ajax提交。所以在App.class.php又增加了IS_AJAX2的定义

switch ($_SERVER['HTTP_ACCEPT']){//定义常量IS_AJAX2 用于判断ajax跨域提交
   case 'application/json, text/javascript, */*':
       //  JSON 格式
       define('IS_AJAX2',true);
       break;
   case 'text/javascript, application/javascript, */*':
       // javascript JSONP 格式
       define('IS_AJAX2',true);
       break;
   case 'text/html, */*':
       //  HTML 格式
       break;
   case 'application/xml, text/xml, */*':
       //  XML 格式
       break;
}

并修改Controller.class.php中dispatchJump函数

private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) {
   if(true === $ajax || IS_AJAX ||IS_AJAX2) {//IS_AJAX2 用于判断ajax跨域提交

这样问题就彻底解决了,但因为改动了框架函数,对于以后升级带了不便,不知道有没有其他更好的方案。

还有另一个需要修改的地方就是Controller.class.php中的ajaxReturn函数也要增加header("Access-Control-Allow-Origin:*"),不然的使用$this->ajaxreturn也不支持跨域

protected function ajaxReturn($data,$type='',$json_option=0) {
   if(empty($type)) $type  =   C('DEFAULT_AJAX_RETURN');
   switch (strtoupper($type)){
       case 'JSON' :
           // 返回JSON数据格式到客户端 包含状态信息
           
header('Content-Type:application/json; charset=utf-8');
           header("Access-Control-Allow-Origin:*");//用于解决前台ajax跨域请求 libo
           exit(json_encode($data,$json_option));
       case 'XML'  :
           // 返回xml格式数据
           
header('Content-Type:text/xml; charset=utf-8');
           exit(xml_encode($data));
       case 'JSONP':
           // 返回JSON数据格式到客户端 包含状态信息
           
header('Content-Type:application/json; charset=utf-8');
           header("Access-Control-Allow-Origin:*");//用于解决前台ajax跨域请求 libo
           $handler  =   isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER');
           exit($handler.'('.json_encode($data,$json_option).');');  
       case 'EVAL' :

 再说一下前台的$.ajax需要注意的就是 在IE10中textStatus一直为parsererror,导致结果一直为error,测试发现是浏览器安全设置问题。然后在jquery官方找到了$.ajax的crossDomain: true,这个参数,但还是没效果。最后用了jQuery.support.cors = true;

        jQuery.support.cors = true;//提供了这样的方式来支持浏览器的跨站请求 IE10有效
        $.ajax({
            url: "http://xxxx/Home/index/ajaxlogin",
            data: {"uid":$name,"upw":$pw},
            timeout: 5000,
            cache: false,
            type: "POST",
            dataType: "json",//如果返回类型与dataType不同,会使textStatus为parsererror而导致执行error函数
            crossDomain: true,//Jquery1.5之后,提供了这样的方式来支持浏览器的跨站请求。(经测试IE10及以下无效,但在ajax请求前设置jQuery.support.cors = true;有效)

转载于:https://my.oschina.net/u/2403409/blog/471809

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值