每天都得找点乐子,今天的乐子就是“WEB开发中前端与后端通信的解决方案”。
首先,说一下“神圣”的需求。假设,我们面前是一个报名活动的页面。所有的逻辑都发生在这报名按钮上,下面是导图:
做法一
按钮是一个链接,当我们用可爱的手指轻轻触碰它时。它会告诉浏览器,我是一个链接。之后,浏览器被跳转到一个新的地址上。与此同时,后端会执行当前的逻辑,渲染对应的 WEB 页面。
这种做法很糟糕:
1、用户体验不好,跳转页面的吞吐量比较高,加大用户的等待时间
2、同时,也加大服务器的负担
3、代码冗余度较高,需要写若干个前端页面和后端方法
做法二
那么,用 Ajax 来实现前后端的通信(异步)也许是个不错的做法。既然,谈到通信,那么必定要有个标准。那,标准是个什么东西?
举个例子(秒懂!哈哈)
公认的标准脸型
不符合标准的脸型
所以,你知道。如果程序没有标准,是一件多么令人“恼怒”的事情。
需要两个 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 框架。
受教了啊
互相学习!