IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    简谈wordpress中的ajax请求,为什么会一直返回“0”

    李惟发表于 2014-11-27 08:04:45
    love 0

    最近我发布了一款数据导入wordpress的插件,有兴趣的可以看这里:http://levi.cg.am/archives/3759;优化这款插件的时候遇到一个问题,使用ajax向wordpress发起请求,返回回来的始终是0!

    至于这个问题,我放后面谈,先简单说下wordpress的ajax请求。

    发起请求

    wordpress中要发起ajax请求不难,分别需要如下:

    PHP记录一个ajax钩子,以便后续操作:

    
    

    从上面可以得出以下结论:

    1. wordpress是通过add_action记录一个ajax请求的钩子
    2. 钩子的名称前缀必须是“wp_ajax_”
    3. 钩子回调方法中必须通过“exit”或“die”来结束输出(后面会继续说明)
    4. 通过“wp_register_script”注册一个js,用于发起请求

    js发起ajax请求:

    jQuery.ajax({
        type: 'POST',
        url: ajaxurl,
        data: {
            action: 'press_data'
        },
        success: function(res) {
            // get res
        }
    });

    从上面可以得出以下结论:

    • url请求地址为一个固定的变量:ajaxurl
    • 请求的“data”数据中必须有一个“action”属性,属性值必须和之前ajax记录请求的钩子名称对应

    这些并不难,如果说还要增加点花样的话,比如说php传个值让ajax请求时带上,那么可以通过函数:wp_localize_script,如下:

    // 注册一个钩子
    wp_register_script('request_data', plugins_url('request_data.js', __FILE__), array('jquery'));
    
    // 传递一个值
    wp_localize_script('request_data', 'request_data', array(
        'url' => 'http://levi.cg.am'
    ));
    
    // 调用这个js
    wp_enqueue_script('request_data');

    而之前的js也仅需要这么修改即可:

    jQuery.ajax({
        type: 'POST',
        url: ajaxurl,
        data: {
            action: 'press_data',
            form: request_data.url
        },
        success: function(res) {
            // get res
        }
    });

    以上这些都不难,就提到这里,有不明白欢迎留言提问。

    Ajax的流程

    要搞清楚为什么ajax请求一直返回0这个问题,先要搞清楚整个请求流程。

    wordpress注册ajax的流程:

    1. 后台load必要的文件、钩子、函数
    2. 接受add_action请求,根据请求记录所有的钩子,包含ajax钩子
    3. 等待触发

    wordpress触发ajax请求

    1. wordpress接受ajax的地址为/wp-admin/admin-ajax.php
    2. 请求文件前先load必要的文件、钩子、函数(和注册时一样)
    3. 检查action请求,若找不到输出0,结束
    4. 检查并触发系统对应的钩子、ajax请求
    5. 检查action请求并根据用户登录与否进行触发
      • 登录用户触发钩子:wp_ajax_{action_name}
      • 未登录用户触发钩子:wp_ajax_nopriv_{action_name}
    6. 最终输出0,结束请求

    看到这里我想大家应该明白为什么ajax钩子的回调函数中都要以“exit”或“die”来结束输出了吧,如果你不结束输出的话,最终都会返回一个“0”来结束本次请求结果;这样可能会破坏你原有的数据结构

    什么情况下ajax请求返回都是“0”

    在网上搜了下,国内也有人遇到过这个情况,但是他们给出的答案大同小异都是类似“位置不对”,“需要放在最后”;其实这样的答案并不能说正确,可能没有弄明白整个流程顺序

    没有action请求

    js发起ajax请求时候没有action,或者action并不在“data”属性中,例如:

    // 错误示范
    jQuery.ajax(
        action: 'action_name',
        data: {}
    );
    
    // 正确示范
    jQuery.ajax({
        data: { action: 'action_name' }
    });

    钩子名称不正确

    PHP记录钩子的名称不对应,比如说请求名称为“action_name”,那么对应的钩子名称就是“wp_ajax_action_name”

    钩子没有被记录

    在加载钩子前已经返回或终止了程序,这个是我这次本身的问题,我写的plugin中有这么一段代码

    if ( ! defined( 'WP_LOAD_IMPORTERS' ) )
    	return;
    
    add_action('wp_ajax_stop_import', array($import, 'stop'));

    如果你是正常浏览导入页面没有问题,但是如果是从ajax过来的请求呢?他没有定义常量“WP_LOAD_IMPORTERS”哦,那么他会被return掉,而不执行当前plugin中的后续代码,那显然也不会触发对应的ajax请求的钩子;同理,exit也是一样的;

    为了证明我的想法是否正确,我做了以下测试

    if (!isset($_GET['test']))
    {
    	echo 'you can't';
    	exit;
    }
    
    if ( ! defined( 'WP_LOAD_IMPORTERS' ) )
    	return;
    
    // some....

    页面中URL加“&test;”正常浏览,ajax请求流程第2步会加载文件、钩子、函数,当加载到这个文件的时候会因为没有text这个请求,而被终止执行

    钩子没有被触发

    举个例子,我的ajax请求钩子注册在数据导入的钩子中,而我当前并不在数据导入页面,那么显然也是不会触发的

    function cnblog2wp_lv_importer_init()
    {
        add_action('wp_ajax_stop_import', array($import, 'stop'));
    }
    
    add_action('admin_init', 'cnblog2wp_lv_importer_init', 15);

    钩子触发不正确

    前面有提到,注册用户触发的钩子是“wp_ajax_{action_name}”,非注册的用户触发的钩子是:“wp_ajax_nopriv_{action_name}”;如果说你的ajax中cookies不一致,那么很有可能触发的钩子不正确哦;另外还有譬如“跨域”等情况,这个已超出这篇文章讨论范围了,暂且先不深究,如果说你的功能是一样的,你也不妨可以注册两个钩子与之对应的钩子哦。

    如何检测ajax请求

    以前专门写过一篇文章,详细可以查看这里:

    http://levi.cg.am/archives/2324

    这里我列举两个简单的方式来分辨ajax请求:

    // 将特定字符作为请求参数作为判断
    $is_ajax = isset($_GET['is_ajax']);
    
    // 通过url来判断
    strpos($_SERVER['REQUEST_URI'], 'wp-admin/admin-ajax.php') !== false

    wordpress中几个怪异的问题

    如果说wordpress的ajax请求返回0,这个不算怪异,那么下面这几个应该相当诡异了,我们暂且可以看做是wordpress设计上的缺陷。

    慎用exit

    先说一个和主题相关的问题,上面说了ajax请求时必须通过exit、die结束请求。但是请谨慎使用exit或die来终止PHP的进程。如果你有使用“wp_enqueue_script”给模板添加js、css,那么exit很有可能将会阻止输出指定的js、css。

    那在使用exit的情况下,怎么才能正确输出指定js或css?你可以在模板中,直接输出静态资源请求的HTML,例如:

    printf(
        '',
        plugins_url('mod.js', dirname(__FILE__))
    );

    后台模板记得开头先写“wrap”

    
    

    如果你有在后台通过钩子“admin_notices”,输出提示信息。

    • 正确使用状态下,提示信息是在标题的下方(wrap区域里面);
    • 错误使用状态下,提示信息是在标题的上方(wrap区域外面);
    您可能也喜欢:
    AJAX POST&跨域 解决方案 - CORS
    使用PHPRPC实现AJAX安全登录
    从PHP判断浏览器的请求是否是一个ajax请求谈到$_SERVER
    使用ajaxfileupload.js插件实现Ajax方式上传文件
    初识 jQuery Deferred
    无觅


沪ICP备19023445号-2号
友情链接