每天都得找点乐子,今天的乐子就是“WEB开发中前端与后端通信的解决方案”。

首先,说一下“神圣”的需求。假设,我们面前是一个报名活动的页面。所有的逻辑都发生在这报名按钮上,下面是导图:

报名按钮导图 - 胡旭个人博客


做法一


按钮是一个链接,当我们用可爱的手指轻轻触碰它时。它会告诉浏览器,我是一个链接。之后,浏览器被跳转到一个新的地址上。与此同时,后端会执行当前的逻辑,渲染对应的 WEB 页面。

这种做法很糟糕:

1、用户体验不好,跳转页面的吞吐量比较高,加大用户的等待时间

2、同时,也加大服务器的负担

3、代码冗余度较高,需要写若干个前端页面和后端方法

做法二


那么,用 Ajax 来实现前后端的通信(异步)也许是个不错的做法。既然,谈到通信,那么必定要有个标准。那,标准是个什么东西?

举个例子(秒懂!哈哈)

5E2EF8CB-6607-41E6-9B25-CB164FC2A2AB

公认的标准脸型

如花

不符合标准的脸型


所以,你知道。如果程序没有标准,是一件多么令人“恼怒”的事情。

需要两个 PHP 类库:

标准接口:

<?php
namespace Common\Library\Int;
/**
 * For communicating each other.
 *
 * @author genialx
 * @see ErrorMsg
 */
interface ErrorMsgInterface
{
    //============//
    /* Error code */
    //============//

    /**
     * Success.
     *
     * @author genialx
     */
    const ERROR_CODE_0X0001 = 0x0001; // success.

    /**
     * unknown error.
     *
     * @author genialx
     */
    const ERROR_CODE_0X0002 = 0x0002;

    /* Error type */
    const ERROR_TYPE_JSON = 'json'; // for json format
}

实现类库:

<?php
namespace Common\Library\Util;
use Common\Library\Int\ErrorMsgInterface;
/**
 * For returning the message in json.
 *
 * It must implement the interface to communicate each other.
 *
 * @author genialx
 *
 */
class ErrorMsg implements ErrorMsgInterface {
    private $_errCode = '';
    private $_errMsg = '';
    private $_type = 'json';
    private $_return = '';
    private $_data = array();
    /**
     * __call method.
     *
     * @author genialx
     * @param string $methodName
     * @param string $args
     */
    Public function __call($methodName, $args) {
        $this->_data[$methodName] = $args[0];
        return $this;
    }
    /**
     * Set the type.
     *
     * @author genialx
     * @param unknown $type
     */
    public function setType($type = self::ERROR_TYPE_JSON) {
        $this->_type = $type;
    }
    /**
     * Get the type.
     *
     * @author genialx
     * @return string
     */
    public function getType() {
        return $this->_type;
    }
    public function setErrCode($errCode) {
        $this->_errCode = $errCode;
        $this->_setMsg($errCode);
    }
    /**
     * Get the errCode.
     *
     * @author genialx
     * @return string
     */
    public function getErrCode() {
        return $this->_errCode;
    }
    /**
     * Set the errMsg.
     *
     * @author genialx
     * @param unknown $errMsg
     */
    public function setErrMsg($errMsg) {
        $this->_errMsg = $errMsg;
    }
    /**
     * Get the errMsg.
     *
     * @author genialx
     * @return string
     */
    public function getErrMsg() {
        return $this->_errMsg;
    }
    /**
     * Get the return.
     *
     * @author genialx
     * @return string
     */
    public function getReturn() {
        if ($this->_errCode == '') return $this->_getUnknowReturn();
        switch ($this->_type) {
            case self::ERROR_TYPE_JSON:
                return $this->_getJSON();;
            break;
            default:
                return $this->_getUnknowReturn();
            break;
        }
    }
    /**
     * Get the return in the json format, according to the private vars.
     *
     * @return string
     */
    private function _getJSON() {
        $json = array('errCode' => $this->getErrCode(), 'errMsg' => $this->getErrMsg());
        if (count($this->_data)) {
            $json = array_merge($json, $this->_data);
        }
        return json_encode($json);
    }
    /**
     * Get the message according to the error code.
     *
     * @author genailx
     */
    private function _setMsg($errCode = null) {
        if (!isset($errCode)) {
            $errCode = $this->_errCode;
        }
        if ($this->_errMsg != '') return false;
        switch ($errCode) {
            case self::ERROR_CODE_0X0001:
                $this->setErrMsg('Success.');
            break;
            case self::ERROR_CODE_0X0002:
                $this->setErrMsg('Unknown error.');
            break;
            default:
                $this->setErrMsg('Uknown error.');
            break;
        }
    }
    /**
     * Get the unknown return in json format.
     *
     * @author genailx
     * @return string
     */
    private function _getUnknowReturn() {
        $json = array("errCode" => self::ERROR_CODE_0X0002, "errMsg" => "Unknown error.");
        return json_encode($json);
    }
    /**
     * Get the return of the success case.
     *
     * @author genailx
     * @return string
     */
    public function getSuccessReturn() {
        $this->_errCode = self::ERROR_CODE_0X0001;
        return $this->getReturn();
    }
}

后端:

<?php
namespace API\Controller;
use Common\Library\Util\ErrorMsg;

class Web extends Controller
{
    /**
     * 参加活动.
     *
     */
    public function addActivity()
    {
        /* 初始化局部变量 */
        $EM = new ErrorMsg();
        // check 
        if (true) {
            $EM->setErrCode($EM::ERROR_CODE_0X0001);
            $EM->setType($EM::ERROR_TYPE_JSON);
            $EM->setErrMsg("successful message to show.");
            $EM->getReturn();
            return true;
        } else {
            $EM->setErrCode($EM::ERROR_CODE_0X0002);
            $EM->setType($EM::ERROR_TYPE_JSON);
            $EM->setErrMsg("failed message to show.");
            $EM->getReturn();
            return false;
        }
    }
}

前端 HTML:

<script type="text/javascript" src="add-activity.js"></script>
<script>
$(function () {
    homeUrl = "__HOME_URL__";
    addActivit.init(); // 初始化操作
});
</script>

前端Javascript:

var _homeUrl = '';

var addActivity = {

  // 注册事件
  var triggerEvents = function() {
      $("#add-button").on("touchstart", function() {
          var parameters = $("#parameters").val();
          $.get(_homeUrl + "/API/Web/addActivity?parameters=" + parameters, function(result) {
              var json = $.parseJSON(result); // 解析来自后台的json字符串
              // 根据返回码,执行相应动作
              switch(json.errCode) {
                  case 0x0001:
                  // some statements...
                  break;
                  case 0x0002:
                  // some statements...
                  break;
                  default:
                  // some statements...
                  break;
              }
          });
      });
  };

  return {
    init: function(homeUrl) {
      _homeUrl = homeUrl;
      triggerEvents(); //注册事件
    };
  };
}();

完善


当然,这个模式可以根据不同项目做少许改变。

目前,也许会遇到这样的问题。当逻辑比较复杂时,那么注册在这个”加入“按钮上的事件函数的处理逻辑,会通过多次请求服务器来判断当前的状态(是或否)。这种情况,对于编码和用户体验(延时等待)都不是好的。所以,其实也可以在报名页面渲染时,把必要的字段放在 input[type=’hidden’] 中。这样,也就解决了前端页面通过 Ajax 多次请求服务器的问题。

注:该文章代码均为伪代码,不可直接复用。文中 PHP 类库样例代码基于 ThinkPHP 框架。

Share:

2 comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.