使用 XMLHttpRequest(二):编码请求主体


表单编码的请求

表单数据编码格式有一个正式的 MIME 类型:

application/x-www-form-urlencoded

因此,提交表单时会自动对表单数据进行编码。一个简单的表单编码字符串如下:

find=pizza&zipcode=02134&radius=1km

但是通过 XMLHttpRequest 对象发送请求时,发送给服务器的可能是一个 JavaScript 对象,需要我们手动对其进行编码:

// 发送 POST 请求
function postData(url, data, callback) {
  var request = new XMLHttpRequest();
  request.open("POST", url);
  request.onreadystatechange = function () {
    if (request.readyState === 4) {
      callback(request);
    }
  };
  request.setRequestHeader("Content-Type", "application/x-www-form-encoded");
  request.send(encodeFormData(data));
}

// 发送 GET 请求
function getData(url, data, callback) {
  var request = new XMLHttpRequest();
  request.open("GET", url + "?" + encodeFormData(data));
  request.onreadystatechange = function () {
    if (request.readyState === 4 && callback) {
      callback(request);
    }
  };
  request.send(null);
}

// 对数据进行编码
function encodeFormData(data) {
  if (!data)
    return "";
  var pairs = [];
  for (var name in data) {
    if (!data.hasOwnProperty(name))
      continue;
    if (typeof data[name] === "function")
      continue;
    var value = data[name].toString();
    name = encodeURIComponent(name.replace("%20", "+"));
    value = encodeURIComponent(value.replace("%20", "+"));
    pairs.push(name + "=" + value);
  }
  return pairs.join("&");
}

JSON 编码的请求

function postJSON(url, data, callback) {
  var request = new XMLHttpRequest();
  request.open("POST", url);
  request.onreadystatechange = function () {
    if (request.readyState === 4 && callback)
      callback(request);
  };
  request.setRequestHeader("Content-Type", "application/json");
  request.send(JSON.stringify(data));
}

XML 编码的请求

function postQuery(url, what, where, radius, callback) {
  var request = new XMLHttpRequest();
  request.open("POST", url);
  request.onreadystatechange = function () {
    if (request.readyState === 4 && callback)
      callback(request);
  };
  // 创建一个XML文档
  var doc = document.implementation.createDocument("", "query", null);
  var query = doc.documentElement;
  var find = doc.createElement("find");
  query.appendChild(find);
  find.setAttribute("zipcode", where);
  find.setAttribute("radius", radius);
  find.appendChild(doc.createTextNode(what));

  request.send(doc);  // 此时 Content-Type 头会自动设置
}

上传文件

XHR2 API 允许通过向 send() 方法传入 File 对象来实现文件上传:

whenReady(function () {
  var elts = document.getElementsByTagName("input");
  for (var i = 0; i < elts.length; i++) {
    var input = elts[i];
    if (input.type !== "file")
      continue;
    var url = input.getAttribute("data-uploadto");
    if (!url) {
      continue;
    }

    input.addEventListener("change", function () {
      var file = this.files[0];
      if (!file)
        return;
      var xhr = new XMLHttpRequest();
      xhr.open("POST", url);
      xhr.send(file);
    }, false);
  }
});

multipart/form-data 请求

当 HTML 表单同时包含文件上传元素和其他元素时,浏览器不能使用普通的表单编码而必须使用 multipart/form-data 这种特殊的 Content-Type 来提交表单。

XHR2 API 中定义了新的 FormData API,通过它可以很容易实现多部分请求主体:

function postFormData(url, data, callback) {
  if (typeof FormData === "undefined")
    throw new Error("FormData is not implemented");

  var request = new XMLHttpRequest();
  request.open("POST", url);
  request.onreadystatechange = function () {
    if (request.readyState === 4 && callback)
      callback(request);
  };

  var formdata = new FormData();
  for (var name in data) {
    if (!data.hasOwnProperty(name))
      continue;
    var value = data[name];
    if (typeof value === "function")
      continue;
    formdata.append(name, value);
  }

  request.send(formdata);  // 自动设置 Content-Type 为 multipart/form-data
}

点赞 取消点赞 收藏 取消收藏

<< 上一篇: 使用 XMLHttpRequest(一):发送请求获取响应

>> 下一篇: 使用 XMLHttpRequest(三):HTTP 进度事件