你现在的位置:首页 > PHP网站建设知识库 > ZenCart > 正文

zencart二次开发

zencart与oscommerce在某中意义上很相似,可以看做是一个升级版,两者之间共用了很多相同的函数或类,不同的是他们是按照不同的方式组织在一起

zencart目录结构

admin后台管理目录
cache 缓存目录
docs 文档目录
download 用于存放下载类商品
editors 所见即所得编辑器
email 电子邮件模版目录
extras 测试文件目录
images 商品图片目录
includes 前台
media 媒体类商品目录
pub 公用目录(空)
 
includes里面的目录:
auto_loaders 自动加载的脚本
classes 主要的类函数
extra_cart_actions 空
extra_configures 第三方模块设置文件
extra_datafiles 第三方模块数据表名定义
functions 主要的功能函数
index_filters 过滤功能
init_includes 初始化功能
languages 语言文件包目录
modules 所有的模块目录
templates 模版目录
 

zencart 采用摸板,单一文件index.php入口,后面跟参数,参数决定显示的内容,基本上网页变换的部分只是中间的主区域
 
重点介绍几个文件
 
includes目录,该目录无疑是zencart的核心(前台),
 
通常情况下index.php第一句话则是包含include目录下的application_top.php文件,如:require('includes/application_top.php');
 
在该系统中application_top.php负责的是初始化工作,比如加载配置文件include('includes/configure.php');如果系统程序没检测到该文件的存在则会尝试调用安装文件
 
,然后它会自动遍历include/extra_configures下的配置文件并包含进来
 
在加载了系统配置文件以后接下来是一个非常重要的文件,这也导致了zencart和oscommerce感觉上很大不同的原因(事实上都一回事)
 
首先调用一个文件require('includes/initsystem.php'); 在initsystem.php中最先加载include/auto_loaders/config.core.php,config.core.php 是一个二围数组$autoLoadConfig,即以数组的形式保存文件的信息供后面文件调用,然后系统会接着加载完 include/auto_loaders目录下所有文件名匹配$loaderPrefix(默认为config)的文件
 
上 面程序执行完以后就可以加载自动执行程序了require('includes/autoload_func.php');在这里它会遍 历$autoLoadConfig数组,它最终执行的效果会包含所有必须用到的函数或者类的定义,还有变量的初始化,config.core.php里面 的注释比较清楚比如 $autoLoadConfig[0][] = array('autoType'=>'class','loadFile'=>'class.base.php');在 autoload_func.php里面执行完以后的效果就是require(DIR_WS_CLASSES . 'class.base.php'),事实上本人是不赞成这种写法,大部分的初始化化工作是通过包含init_includes目录下的文件来实现的
 
如: $autoLoadConfig[110][] = array('autoType'=>'init_script','loadFile'=> 'init_templates.php');它在执行完autoload_func.php文件后就已经加载了init_includes目录下的 init_templates.php
 
文件,由于里面包含的文件太多,在这就不做一一介绍了
 
下面我来介绍下zencart是怎么根据摸版把内容显示出来的
 
require('includes/application_top.php');初始化所以需要用到的公共信息以后接下来就应该是显示了
 
在index.php的第29行有句$directory_array = $template->get_template_part($code_page_directory, '/^header_php/'); 
 
由于所有初始化工作已经完成,所有我们就可以在上面的文件找到他们的定义,如 $autoLoadConfig[100][] = array('autoType'=>'classInstantiate','className'=>'template_func','objectName'=>'template');
 
在这里就定义了$template = new template_func(); ,然后$code_page_directory变量的定义是在init_includes/init_sanitize.php文件中定义在这里必须要对class/template_func.php中定义的template_func类比较熟悉,在改类中主要定义了两个方法get_template_dir()和get_template_part();这两个方法在zencart的摸版中起到了决定性的作用
 
我简单的说下get_template_dir方法function get_template_dir($template_code, $current_template, $current_page, $template_dir, $debug=false),它定义了5个参数,第一个参数一般是个文件名,它是用来判断后两个参数组成的目录中有没有匹配$template_code的这个文件,该类复写了默认的系统函数file_exists所以很多初学者可能会比较迷惑
 
function get_template_dir($template_code, $current_template, $current_page, $template_dir, $debug=false) {
 
    //        echo 'template_default/' . $template_dir . '=' . $template_code;
 
    if ($this->file_exists($current_template . $current_page, $template_code)) { 
 
      return $current_template . $current_page . '/';
 
    } elseif ($this->file_exists(DIR_WS_TEMPLATES . 'template_default/' . $current_page, ereg_replace('/', '', $template_code), $debug)) {
 
      return DIR_WS_TEMPLATES . 'template_default/' . $current_page;
 
    } elseif ($this->file_exists($current_template . $template_dir, ereg_replace('/', '', $template_code), $debug)) {
 
      return $current_template . $template_dir;
 
    } else {
 
      return DIR_WS_TEMPLATES . 'template_default/' . $template_dir; 
 
      //        return $current_template . $template_dir;
 
    }
 
}
 
/*
 

 
includes/templates/zccn/index
 
includes/templates/template_default/index
 
includes/templates/zccn/common
 
includes/templates/template_default/common
 
*/
 
get_template_part()方法有两个函数,第一个参数是文件目录,第二个参数是匹配的条件,执行的结果是包含该目录下所有文件名匹配这个条件的文件
 
比如$directory_array = $template->get_template_part($code_page_directory, '/^header_php/');
 
这句话执行的结果就是返回目录下$code_page_directory所有文件名以header_php开头的文件 如此时的url(http://localhost/zencart/index.php?main_page=product_info&cPath=49_27&products_id=83)
 
你现在应该查看init_sanitize.php中$code_page_directory的定义此时的$code_page_directory的值应该是includes/modules/product_info/
 
所以它就应该包含该目录下所有以header_php开头的文件,在这里好象就只有一个header_php.php
 
$directory_array = $template->get_template_part($code_page_directory, '/^header_php/');这个包含文件其实是初始化前台不同页面显示所需要用到的变量函数,主要是初始化数据库的东西,因为每个页面需要的数据资料都有可能不同,所以index.php?main_page=index 当main_page的值不同是在includes/modules/目录下都会有个对应的目录,这里是index目录
 
只要知道了这两个方法的用法,你就会知道模板文件都是怎么显示出来的了
 
再 来解释一 require($template->get_template_dir('html_header.php',DIR_WS_TEMPLATE, $current_page_base,'common'). '/html_header.php');
 
假设当前http://localhost/zencart/index.php?main_page=index&cPath=48
 
DIR_WS_TEMPLATE 定义是在includes/init_templates.php中定义define('DIR_WS_TEMPLATE', DIR_WS_TEMPLATES . $template_dir . '/');,因为我现在用的是默认的zccn模板
 
所以现在的DIR_WS_TEMPLATE=includes/templates/zccn/
 
$current_page_base在这里已经就是index
 
上面已经解释了$template->get_template_dir()的方法了
 
程序会依次在includes/templates/zccn/index
 
includes/templates/template_default/index
 
includes/templates/zccn/common
 
includes/templates/template_default/common
 
这四个目录下找html_header.php,在这里,最终在template_default\common目录下找到html_header.php
 
到这里就可以自己写摸板文件了,因为$template->get_template_dir()是按顺序找的,所以你只要在你的模板文件中存在该文件即可

zencart的sidebox机制
zencart的左右边栏很有特色,由一块一块的sidebox拼合起来的,在模板的sidebox文件夹建立一个sidebox程序,登陆管理后台后, 选择外 观控制,系统会自动检测到新增加的sidebox程序,并提醒你操作。并把所有的sidebox配置信息存储在layout_boxes的表格中。
程序调用边栏是通过includes/modules 目录下的column_left.php,和column_right.php 控制。分析下源码也非常简单:首页查询layout_boxes数据表,检索出在左栏和或右栏显示的所有sidebox,再直接require 进来 layout_box_name 字段标记的sidebox名称。随便打开一个sidebox的源代码,如系统自带的includes/modules/sideboxes /banner_box.php,banner_box.php只要用来获取sidebox显示所要的数据,再通过 require($template->get_template_dir(’tpl_banner_box.php’,DIR_WS_TEMPLATE, $current_page_base,’sideboxes’),载入显示这个sidebox的模板,其实这个所谓的模板就是生成一个$content 的字符串,然后再require($template->get_template_dir($column_box_default, DIR_WS_TEMPLATE, $current_page_base,’common’) . ‘/’ . $column_box_default) 再用一个显示sidebox的公共模板,在$column_box_default中打印出$content的内容,这样一个sidebox就显示完成 了!
如何添加一个自己的sidebox?其实很简单,在includes/modules/sideboxes/{模板目录}/  建立一个文件,就是一个 sidebox了,可以在后台控制是否显示在默认的左右边栏和排序 。在这个文件中就输出任何内容了,当然可以按照标准的模式,再在includes/templates/{模板目录}/sideboxes 下建立一个模板文件require进来,尽量做到 M/V的分离,这样以后修改也会比较方便!
在zencart左侧栏目中,每个小模块都是用box方式显示的。zencart 函数zen_get_box_id()主要是对box_id进行处理. while (strstr($box_id, '_')) $box_id = str_replace('_', '', $box_id); $box_id = str_replace('.php', '', $box_id); return $box_id; 看的出来,他的主要作用是除去"_"和".phquot;的后缀,形成一个新的字符串,形成的注释中会有<!--// bof: <?php echo $box_id; ?> //--> <div cla="leftBoxContainer" id="lt;?php echo str_replace('_', '-', $box_id ); ?>quot; style="width: <?php echo $column_width; ?>quotgt; <h3 cla="leftBoxHeading" id="lt;?php echo str_replace('_', '-', $box_id) . 'Heading'; ?>quotgtlt;?php echo $title; ?>lt;/h3>借助$box_id还可以形成样式html 的id            

 

 

前台首页分析
Index.php加载需要的所有文件,简称入口文件。
 /* main_template_vars.php 会根据$_GET['main_page'] 显示不同的模板*/ 
require($template->get_template_dir('main_template_vars.php',DIR_WS_TEMPLATE, $current_page_base,'common'). '/main_template_vars.php');

后台首页分析  
首部导航菜单栏  机制
index.php->header.php->header_navigation.php->
includes/boxes/**.dhtml.php->
function zen_draw_admin_box($za_heading, $za_contents)

二次开发导航实例  

 主要改动tpl_main_page.php(改后非zencart的tpl_main_page.php,为了继承系统功能应用,需要为tpl_main_pages.php提供页面参数判断转入功能。但还是有index.php入口文件引导)
定义整个页面样式 ,可以定义自己的整个风格和数据库操作(更改了zencart的MVC模式,使页面和业务逻辑处于同一个请求页面),如果需要用到zencart本身的功能,则重新定义一个tpl_main_pages.php(属于zencart的tpl_main_page.php的重命名同文件—-至少保留$body_code中心部位,由自定义tpl_main_page.php页面转入) 。
Tpl_header.php和tpl_footer.php可以自定义其页面,
一般还有自定义左右分栏tpl_left.php和tpl_right.php(以上文件供自定义tpl_main_page.php引入使用)
    经过页面改动,自定义页面上的url基本硬编码路径。     

☆    Zencart 类和函数及特别变量分析
1./*获取模板目录$page_directory下,含$template_part并后缀为.php的文件*/
Function get_template_part($page_directory, $template_part, $file_extension = '.php') {
    $directory_array = array();
    if ($dir = @dir($page_directory)) {
      while ($file = $dir->read()) {
        if (!is_dir($page_directory . $file)) {
         if (substr($file, strrpos($file, '.')) == $file_extension && preg_match($template_part, $file)) {
            $directory_array[] = $file;
         }
        }
      }

      sort($directory_array);
      $dir->close();
    }
    return $directory_array;
  }
  


2/*获取当前模板($current_template/$current_page或者$current_template/$template_dir或者DIR_WS_TEMPLATES . 'template_default/' . $template_dir组成的模板目录文件)含$template_code的文件的目录*/
function get_template_dir($template_code, $current_template, $current_page, $template_dir, $debug=false) {
    //    echo 'template_default/' . $template_dir . '=' . $template_code;
    if ($this->file_exists($current_template . $current_page, $template_code)) {
      return $current_template . $current_page . '/';
    } elseif ($this->file_exists(DIR_WS_TEMPLATES . 'template_default/' . $current_page, preg_replace('/\//', '', $template_code), $debug)) {
      return DIR_WS_TEMPLATES . 'template_default/' . $current_page;
    } elseif ($this->file_exists($current_template . $template_dir, preg_replace('/\//', '', $template_code), $debug)) {
      return $current_template . $template_dir;
    } else {
      return DIR_WS_TEMPLATES . 'template_default/' . $template_dir;
      //        return $current_template . $template_dir;
    }
  }

/**
3 * method to do bind variables to a query 将字符串$sql中的$bindVarString绑定为值$bindVarValue且类型为$bindVarType
**/
  function bindVars($sql, $bindVarString, $bindVarValue, $bindVarType, $debug = false) {
    $bindVarTypeArray = explode(':', $bindVarType);
    $sqlNew = $this->getBindVarValue($bindVarValue, $bindVarType);
    $sqlNew = str_replace($bindVarString, $sqlNew, $sql);
    return $sqlNew;
  }


/*传递参数(&$rent_page_number,每页数量$max_rows_per_page,原始&$sql_query,要显示的结果总数&$query_num_rows),返回新的$sql_query .= " limit " . $offset . ", " . $max_rows_per_page和$query_num_rows以及$num_pages、$offset*/
function splitPageResults(&$current_page_number, $max_rows_per_page, &$sql_query, &$query_num_rows) {
     …….
      $reviews_count = $db->Execute($sql);

      $query_num_rows = $reviews_count->fields['total'];

      $num_pages = ceil($query_num_rows / $max_rows_per_page);
      if ($current_page_number > $num_pages) {
        $current_page_number = $num_pages;
      }
      $offset = ($max_rows_per_page * ($current_page_number - 1));

// fix offset error on some versions
      if ($offset < 0) { $offset = 0; }

      $sql_query .= " limit " . $offset . ", " . $max_rows_per_page;
    }

 

/*展示一个翻页链接*/
function display_links($query_numrows, $max_rows_per_page, $max_page_links, $current_page_number, $parameters = '', $page_name = 'page') {}


/*展示显示的商品是第几个$from_num到第几个$to_num */
function display_count($query_numrows, $max_rows_per_page, $current_page_number, $text_output) {….. return sprintf($text_output, $from_num, $to_num, $query_numrows);}
    }

/*返回session*/
Function zen_session_name()

/*给定数组参数以url参数形式返回*/
function zen_get_all_get_params($exclude_array = '') {}

/*以图片作为一个提交按钮的html输出,$parameters 一般设置id和name值**/
function zen_image_submit($image, $alt = '', $parameters = ''){}

 

$current_page = $_GET['main_page'];
  $current_page_base = $current_page;
 $code_page_directory = DIR_WS_MODULES . 'pages/' . $current_page_base;

AJAX应用
最近互联网上比较火热的话题当然是关于WEB2.0的应用,其中AJAX又是WEB2.0的核心之一。AJAX是Asynchronous javascript and XML 的缩写。它并不是一门新的语言或技术,它实际上是几项技术按一定的方式组合在一在同共的协作中发挥各自的作用,它包括
使用XHTML和CSS标准化呈现;
使用DOM实现动态显示和交互;
使用XML和XSLT进行数据交换与处理;
使用XMLHttpRequest进行异步数据读取;
最后用javascript绑定和处理所有数据;
Ajax的工作原理相当于在用户和服务器之间加了—个中间层,使用户操作与服务器响应异步化。这样把以前的一些服务器负担的工作转嫁到客户端,利于客户端闲置的处理能力来处理,减轻服务器和带宽的负担,从而达到节约ISP的空间及带宽租用成本的目的。

我们以两个验证通行证帐号是否存在的例子来讲述AJAX在实际中的应用:

(1)    用文本字符串的方式返回服务器的响应来验证网易通行证帐号是否存在; 
(2)    以XMLDocument对象方式返回响应来验证金山通行证帐号是否存在;

首 先,我们需要用javascript来创建XMLHttpRequest 类向服务器发送一个HTTP请求, XMLHttpRequest 类首先由Internet Explorer以ActiveX对象引入,被称为XMLHTTP。 后来Mozilla﹑Netscape﹑Safari 和其他浏览器也提供了XMLHttpRequest类,不过它们创建XMLHttpRequest类的方法不同。

对于Internet Explorer浏览器,创建XMLHttpRequest 方法如下:
xmlhttp_request = new ActiveXObject("Msxml2.XMLHTTP.3.0"); //3.0或4.0, 5.0        
xmlhttp_request = new ActiveXObject("Msxml2.XMLHTTP");
xmlhttp_request = new ActiveXObject("Microsoft.XMLHTTP");

由于在不同Internet Explorer浏览器中XMLHTTP版本可能不一致,为了更好的兼容不同版本的Internet Explorer浏览器,因此我们需要根据不同版本的Internet Explorer浏览器来创建XMLHttpRequest类,上面代码就是根据不同的Internet Explorer浏览器创建XMLHttpRequest类的方法。

对于Mozilla﹑Netscape﹑Safari等浏览器,创建XMLHttpRequest 方法如下:
                xmlhttp_request = new XMLHttpRequest();


如果服务器的响应没有XML mime-type header,某些Mozilla浏览器可能无法正常工作。 为了解决这个问题,如果服务器响应的header不是text/xml,可以调用其它方法修改该header。
xmlhttp_request = new XMLHttpRequest();
xmlhttp_request.overrideMimeType('text/xml');


在实际应用中,为了兼容多种不同版本的浏览器,一般将创建XMLHttpRequest类的方法写成如下形式:
    try{
        if( window.ActiveXObject ){
            for( var i = 5; i; i-- ){
                try{
                    if( i == 2 ){
xmlhttp_request = new ActiveXObject( "Microsoft.XMLHTTP" );    
                    }else{
xmlhttp_request = new ActiveXObject( "Msxml2.XMLHTTP." + i + ".0" );    
                    }
xmlhttp_request.setRequestHeader("Content-Type","text/xml");
xmlhttp_request.setRequestHeader("Content-Type","gb2312");
break;}
                catch(e){                        
                    xmlhttp_request = false;
                }
            }
        }else if( window.XMLHttpRequest ){
            xmlhttp_request = new XMLHttpRequest();
            if (xmlhttp_request.overrideMimeType) {
                xmlhttp_request.overrideMimeType('text/xml');
            }
        }
    }catch(e){
        xmlhttp_request = false;
    }


在定义了如何处理响应后,就要发送请求了。可以调用HTTP请求类的open()和send()方法,如下所示:
xmlhttp_request.open('GET', URL, true);
xmlhttp_request.send(null);


open()的第一个参数是HTTP请求方式—GET,POST或任何服务器所支持的您想调用的方式。 按照HTTP规范,该参数要大写;否则,某些浏览器(如Firefox)可能无法处理请求。 
第二个参数是请求页面的URL。
第三个参数设置请求是否为异步模式。如果是TRUE,javascript函数将继续执行,而不等待服务器响应。这就是"AJAX"中的"A"。 

用 javascript来创建XMLHttpRequest 类向服务器发送一个HTTP请求后,接下来要决定当收到服务器的响应后,需要做什么。这需要告诉HTTP请求对象用哪一个javascript函数处理这 个响应。可以将对象的onreadystatechange属性设置为要使用的javascript的函数名,如下所示:
xmlhttp_request.onreadystatechange =FunctionName;


FunctionName是用javascript创建的函数名,注意不要写成FunctionName(),当然我们也可以直接将javascript代码创建在onreadystatechange之后,例如:
xmlhttp_request.onreadystatechange = function(){
    // javascript代码段
};


在这个函数中。首先要检查请求的状态。只有当一个完整的服务器响应已经收到了,函数才可以处理该响应。XMLHttpRequest 提供了readyState属性来对服务器响应进行判断。

readyState的取值如下: 
0 (未初始化) 
1 (正在装载) 
2 (装载完毕) 
3 (交互中) 
4 (完成)

所以只有当readyState=4时,一个完整的服务器响应已经收到了,函数才可以处理该响应。具体代码如下:
if (http_request.readyState == 4) {
    // 收到完整的服务器响应
} else {
    // 没有收到完整的服务器响应
}


当readyState=4时,一个完整的服务器响应已经收到了,接着,函数会检查HTTP服务器响应的状态值。完整的状态取值可参见W3C文档。当HTTP服务器响应的值为200时,表示状态正常。

在检查完请求的状态值和响应的HTTP状态值后,就可以处理从服务器得到的数据了。有两种方式可以得到这些数据:

(1)    以文本字符串的方式返回服务器的响应 
(2)    以XMLDocument对象方式返回响应 

实例一: 用文本字符串的方式返回服务器的响应来验证网易通行证帐号是否存在

首先,我们登陆网易通行证注册页面,可以看到检测用户名是否存在是将用户名提交给checkssn.jsp页面进行判断,格式为:
reg.163.com/register/checkssn.jsp?username=用户名 

根据上面讲到的方法,我们可以利用AJAX技术对网易通行证用户名进行检测:

第一步:新建一个基于Xhtml标准的网页,在<head>区域插入javascript函数如下:
<script type="text/javascript" language="javascript">
function getXMLRequester( ){
    var xmlhttp_request = false;
    try{
        if( window.ActiveXObject ){
            for( var i = 5; i; i-- ){
                try{
                    if( i == 2 ){
xmlhttp_request = new ActiveXObject( "Microsoft.XMLHTTP" );    
                    }else{
xmlhttp_request = new ActiveXObject( "Msxml2.XMLHTTP." + i + ".0" );    
xmlhttp_request.setRequestHeader("Content-Type","text/xml");
xmlhttp_request.setRequestHeader("Content-Type","gb2312");
                 }
break;}
                catch(e){                        
                    xmlhttp_request = false;
                }
            }
        }else if( window.XMLHttpRequest ){
            xmlhttp_request = new XMLHttpRequest();
            if (xmlhttp_request.overrideMimeType) {
                xmlhttp_request.overrideMimeType('text/xml');
            }
        }
    }catch(e){
        xmlhttp_request = false;
    }
    return xmlhttp_request ;
}

    function IDRequest(n) {//定义收到服务器的响应后需要执行的javascript函数
url=n+document.getElementById('163id').value;//定义网址参数
        xmlhttp_request=getXMLRequester();//调用创建XMLHttpRequest的函数
        xmlhttp_request.onreadystatechange = doContents;//调用doContents函数
        xmlhttp_request.open('GET', url, true);
        xmlhttp_request.send(null);
    }
    function doContents() {
        if (xmlhttp_request.readyState == 4) {// 收到完整的服务器响应
            if (xmlhttp_request.status == 200) {//HTTP服务器响应的值OK
document.getElementById('message').innerHTML = xmlhttp_request.responseText;
//将服务器返回的字符串写到页面中ID为message的区域
            } else {
                alert(http_request.status);
            }
        }
    }
</script>


在<body>区域建立一个文本框,id为163id
<input type="text" id="163id" onpropertychange="IDRequest('http://reg.163.com/register/checkssn.jsp?username=')" />


再建一个id为messsge的空白区域用来显示返回字符串(也可以通过javascript函数截取一部分字符串显示):

<div id="message"></div>

这样,一个基于AJAX技术的用户名检测页面就做好了,不过这个页面将返回服务器响应生成页面的所有字符串,当然还可以对返回的字符串进行一些操作,便于应用到不同的需要当中。

实例二: 以XMLDocument对象方式返回响应来验证金山通行证帐号是否存在

在 上面的例子中,当服务器对HTTP请求的响应被收到后,我们会调用请求对象的reponseText属性。该属性包含了服务器返回响应文件的内容。现在我 们以XMLDocument对象方式返回响应,此时将不再需要reponseText属性而使用responseXML属性。

首先登陆金山通行证注册页面,我们发现金山通行证用户名的检测方式为:
pass.kingsoft.com/ksgweb/jsp/login/uid.jsp?uid=用户名,并且返回XML数据:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
<response>
<method>isExistedUid</method> 
<result>-2</result> 
</response>


当result值为-1时表示此用户名已被注册,当result值为-2时表示此用户名尚未注册,因此通过对result值的判断可以知道用户名是否被注册。

对上例代码进行修改:

首先找到
document.getElementById('message').innerHTML = xmlhttp_request.responseText;


改为:
var response = xmlhttp_request.responseXML.documentElement;
var result = response.getElementsByTagName('result')[0].firstChild.data;//返回result节点数据
if(result ==-2){
document.getElementById('message').innerHTML = "用户名"+document.getElementById('163id').value+"尚未注册";
}
else if(result ==-1){
document.getElementById('message').innerHTML = "对不起,用户名"+document.getElementById('163id').value+"已经注册";
}


通过以上两个实例说明了AJAX的客户端基础应用,采用的是网易和金山现成的服务器端程序,当然为了开发合适自己页面的程序, 还需要对自己编写服务器端程序,这设计到程序语言及数据库的操作,对于有一定程序基础的读者一定不是很难的事情,本文着重讨论了客户端AJAX的应用体 验,广大读者可以根据本文讲的原理结合各种样式表现手法作出绚丽多彩的应用,希望本文能够起到抛砖引玉的作用。
附录

(一) HTTP 1.1支持的状态代码

100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分
101 Switching Protocols 服务器将遵从客户的请求转换到另外一种协议
200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
201 Created 服务器已经创建了文档,Location头给出了它的URL。 
202 Accepted 已经接受请求,但处理尚未完成。 
203 Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝 
204 No Content 没有新文档,浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的
205 Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容
206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它
300 Multiple Choices 客户请求的文档可以在多个位置找到,这些位置已经在返回的文档内列出。如果服务器要提出优先选择,则应该在Location应答头指明。 
301 Moved Permanently 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。 
302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。 
303 See Other 类似于301/302,不同之处在于,如果原来的请求是POST,Location头指定的重定向目标文档应该通过GET提取
304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。 
305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取
307 Temporary Redirect 和302(Found)相同。许多浏览器会错误地响应302应答进行重定向,即使原来的请求是POST,即使它实际上只能在POST请求的应答是303时 才能重定向。由于这个原因,HTTP 1.1新增了307,以便更加清除地区分几个状态代码:当出现303应答时,浏览器可以跟随重定向的GET和POST请求;如果是307应答,则浏览器只 能跟随对GET请求的重定向。 
400 Bad Request 请求出现语法错误。 
401 Unauthorized 客户试图未经授权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,浏览器据此显示用户名字/密码对话框,然后在填写合适的Authorization头后再次发出请求。 
403 Forbidden 资源不可用。
404 Not Found 无法找到指定位置的资源
405 Method Not Allowed 请求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)对指定的资源不适用。
406 Not Acceptable 指定的资源已经找到,但它的MIME类型和客户在Accpet头中所指定的不兼容
407 Proxy Authentication Required 类似于401,表示客户必须先经过代理服务器的授权。
408 Request Timeout 在服务器许可的等待时间内,客户一直没有发出任何请求。客户可以在以后重复同一请求。 
409 Conflict 通常和PUT请求有关。由于请求和资源的当前状态相冲突,因此请求不能成功。
410 Gone 所请求的文档已经不再可用,而且服务器不知道应该重定向到哪一个地址。它和404的不同在于,返回407表示文档永久地离开了指定的位置,而404表示由于未知的原因文档不可用。 
411 Length Required 服务器不能处理请求,除非客户发送一个Content-Length头。 
412 Precondition Failed 请求头中指定的一些前提条件失败
413 Request Entity Too Large 目标文档的大小超过服务器当前愿意处理的大小。如果服务器认为自己能够稍后再处理该请求,则应该提供一个Retry-After头 
414 Request URI Too Long URI太长 
416 Requested Range Not Satisfiable 服务器不能满足客户在请求中指定的Range头
500 Internal Server Error 服务器遇到了意料不到的情况,不能完成客户的请求
501 Not Implemented 服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求 
502 Bad Gateway 服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答 
503 Service Unavailable 服务器由于维护或者负载过重未能应答。例如,Servlet可能在数据库连接池已满的情况下返回503。服务器返回503时可以提供一个Retry-After头 
504 Gateway Timeout 由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答 
505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本

(二) XMLHttpRequest 对象方法 
abort()        停止当前请求
getAllResponseHeaders()    作为字符串返问完整的headers
getResponseHeader("headerLabel")    作为字符串返问单个的header标签
open("method","URL"[,asyncFlag[,"userName"[, "password"]]])    设置未决的请求的目标 URL, 方法, 和其他参数
send(content)    发送请求
setRequestHeader("label", "value")        设置header并和请求一起发送


(三) XMLHttpRequest 对象属性
onreadystatechange            状态改变的事件触发器
readyState                对象状态(integer):
                0 = 未初始化
                1 = 读取中
                2 = 已读取
                3 = 交互中
                4 = 完成
responseText        服务器进程返回数据的文本版本
responseXML        服务器进程返回数据的兼容DOM的XML文档对象
status            服务器返回的状态码, 如:404 = "文件末找到" 、200 ="成功"
statusText        服务器返回的状态文本信息