技术开发 频道

借助 Ajax 自动保存 JSF 表单,第 1 部分: 利用 XMLHttpRequest 提交

  获取及编码表单数据

  AutoSaveScript.js 文件包含一个称为 getFormData() 的 JavaScript 函数,它获取一个 form 对象并对其元素进行迭代以构建包含名称-值对的字符串。这个字符串遵循标准的 application/x-www-form-urlencoded 格式,用 & 分隔参数,并在每个参数的名称和值之间使用 =。内部函数 addParam() 可以对单一参数进行编码,所使用的是 JavaScript API 提供的 escape() 函数。escape() 函数用 % 后跟被编码字符的两位 16 进制码代替了几乎所有非字母数字的 ASCII 字符。 我之所以说 “几乎所有非字母数字的 ASCII 字符”,是因为除此之外,还有字母数字字符以及无编码的其他一些字符(例如 +)。

  例如,如果将字符串 a + b 传递给 escape(),结果将是 a%20+%20b(20 是空格符的 16 进制码)。这是一个符合 RFC 1738 的有效 URL 编码,但如果将这个已编码的字符串提交给服务器端脚本,例如 JSP,结果将是一个空格而不是 + 字符。这也是正确的,因为描述 application/x-www-form-urlencoded 格式的 RFC 1866 中规定空格符的编码为 +,并且所有非字母数字字符都以一个 % 后跟 16 进制码替代。当服务器对这个字符串进行解码时,任何 + 字符都会被还原成一个空格。

  总之,由 escape() 执行的 URL 编码并不完全与 application/x-www-form-urlencoded 一样,因为 escape() 将 + 字符保留,不做编码,而在 application/x-www-form-urlencoded 中,空格则被编码为 + 字符。解决这个问题最简单的方法是将所有 + 字符都编码为 %2B(2B 是 + 的 16 进制代码)。也可以使用 replace() 对 escape() 的返回结果执行此操作。在本例中,可以将字符串 a + b 编码为 a%20%2B%20b。清单 3 所示的是 addParam() 内部函数,它将一个编码后的名称-值对添加到 getFormData() 的本地 dataString 变量。

  清单 3. 对单一请求参数进行编码

function getFormData(form) {
    var dataString
= "";

    
function addParam(name, value) {
        dataString
+= (dataString.length > 0 ? "&" : "")
            
+ escape(name).replace(/\+/g, "%2B") + "="
            
+ escape(value ? value : "").replace(/\+/g, "%2B");
    }
    ...
}

  getFormData() 函数获取 form 对象的 elements 数组,并根据每个元素的类型调用 addParam()。单个名称-值会针对每个文本框、密码和隐藏字段添加。只有当对应的表单元素被选中时,复选框和单选按钮的值才会被编码。如果是列表,单个名称-值对会针对每个选中项添加。之后,getFormData() 会返回包含表单编码数据的字符串(见清单 4)。

  清单 4. 获取和编码表单数据

function getFormData(form) {
    ...
    var elemArray
= form.elements;
    
for (var i = 0; i < elemArray.length; i++) {
        var element
= elemArray[i];
        var elemType
= element.type.toUpperCase();
        var elemName
= element.name;
        
if (elemName) {
            
if (elemType == "TEXT"
                    || elemType
== "TEXTAREA"
                    || elemType
== "PASSWORD"
                    || elemType
== "HIDDEN")
                addParam(elemName, element.value);
            
else if (elemType == "CHECKBOX" && element.checked)
                addParam(elemName,
                    element.value ? element.value :
"On");
            
else if (elemType == "RADIO" && element.checked)
                addParam(elemName, element.value);
            
else if (elemType.indexOf("SELECT") != -1)
                
for (var j = 0; j < element.options.length; j++) {
                    var
option = element.options[j];
                    
if (option.selected)
                        addParam(elemName,
                            
option.value ? option.value : option.text);
                }
        }
    }
    return dataString;
}
0
相关文章