AI智能
改变未来

根据JavaScript中原生的XMLHttpRequest实现jQuery的Ajax


基本介绍

XmlHttpRequest

XmlHttpRequest是JavaScript中原生的,历史悠久的一种发送网络请求的方案。

基本上所有前端框架对于网络请求的部分都是基于它来完成的。

在本章节中我们将了解它的基本用法,并且会实现一个与jQuery.ajax功能百分之九十相似的网络请求组件。

我是没有读过jQuery.ajax源码的,并且我也不是一个专精前端的程序员,所以后面的代码写的可能不太好,仅和大家在此做个交流。

后端代码

为了方便后续代码测试,我们后端采用Python-flask框架来完成。

  • IP:localhost
  • PORT:5700

代码如下:

from logging import debug, errorfrom flask import Flaskfrom flask import requestfrom flask import make_responsefrom flask import jsonifyapp = Flask(__name__)@app.after_request  # 解决CORS跨域请求def cors(response):response.headers[\'Access-Control-Allow-Origin\'] = "*"if request.method == "OPTIONS":# 允许的请求头response.headers["Access-Control-Allow-Headers"] = "Origin,Content-Type,Cookie,Accept,Token,authorization,user_head"return response@app.route("/get", methods=["get"])def get():user_head = request.headers.get("user_head")user_params = request.argsprint(user_params)return jsonify(user_params, user_head)@app.route("/post", methods=["post"])def post():user_head = request.headers.get("user_head")user_params = request.formprint(user_params)return jsonify(user_params, user_head)@app.route("/json", methods=["post"])def json():user_head = request.headers.get("user_head")user_params = request.jsonreturn jsonify(user_params, user_head)@app.route("/file", methods=["post"])def file():file_obj = request.files.get("avatar")if file_obj is None:return make_response(jsonify("unload avatar"), 400)file_name = file_obj.filenamefile_obj.save(file_name)return jsonify("upload avatar success!!")if __name__ == "__main__":app.run(host="localhost", port=5700, debug=True)

open()

open()方法用于创建并返回一个请求对象(单纯创建,并不发送)。

参数释义:

  • method:请求方式
  • url:请求地址
  • async:是否异步请求

注意:如果method为GET方式,则需要我们手动在url中添加参数

请求相关

send()

send()方法用于发送一次网络请求。

参数释义:

  • body:method为POST时携带的请求体数据,必须是字符串类型

注意:如果method为GET方式,则直接xhr.send(null)即可,因为GET请求没有请求体

setRequestHeader()

setRequestHeader()方法用于设置请求头。

参数释义:

  • header:请求头的key
  • value:请求头的value

注意:每次只能设置一组请求头键值对,如果要设置多组请求头键值对请多次调用该方法

abort()

abort()方法用于取消本次网络请求。

响应相关

getAllResponseHeaders()

getAllResponseHeaders()方法用于获取所有响应头数据。

返回的数据类型为字符串。

getResponseHeader()

getResponseHeader()方法用于获取响应头中指定header的value。

返回的数据类型为字符串。

status

status属性用于返回服务端响应的HTTP响应状态码。

以下是常见的HTTP响应状态码:

  • 200:请求成功
  • 404:请求失败,请求的资源错误
  • 500:请求失败,服务器内部出现错误
  • 302:重定向
  • 304:缓存优先

statesText

statesText属性用于返回服务端响应的状态文本。

如OK、NotFound等字样。

responseText

responseText属性用于返回响应体主体内容。

返回的数据类型为字符串。

回调函数

readyState

readyState属性用于返回一个整数类型的状态值,它表明当前xhr对象的请求状态。

共有5种形态:

  • 0:未初始化,尚未调用open()方法
  • 1:已初始化,调用了open()方法,但还未调用send()方法
  • 2:已发送,调用了send()方法,但还未收到服务端响应
  • 3:已接收,已经收到了部分服务端响应数据
  • 4:已完成,已经收到了全部服务端响应数据

readystatechange

readystatechange事件用于设置xhr对象的readState状态发生改变时所执行的回调函数。

简单使用

contentType说明

contentType是HTTP协议中的一个请求头,它包含了浏览器告知后端服务器本次发送数据的格式。

它和<form>表单的enctype参数类似,共有以下一些常见值的选项:

常见的媒体格式类型如下:

  • text/html : HTML格式
  • text/plain :纯文本格式
  • text/xml : XML格式
  • image/gif :gif图片格式
  • image/jpeg :jpg图片格式
  • image/png:png图片格式

以application开头的媒体格式类型:

  • application/xhtml+xml :XHTML格式
  • application/xml: XML数据格式
  • application/atom+xml :Atom XML聚合格式
  • application/json: JSON数据格式
  • application/pdf:pdf格式
  • application/msword : Word文档格式
  • application/octet-stream : 二进制流数据(如常见的文件下载)
  • application/x-www-form-urlencoded : <form enctype=“”>中默认的enctype,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

另外一种常见的媒体格式是上传文件之时使用的:

  • multipart/form-data : 在表单中进行文件上传时,就需要使用该格式

我们接下来会使用2种最主流的格式进行试验:

  • application/x-www-form-urlencoded (默认的GET和POST数据格式)
  • application/json(前端需要发送的JSON格式数据)

GET请求

发送GET请求:

"use strict";let xhr = new XMLHttpRequest();// 绑定回调函数xhr.addEventListener("readystatechange", () => {switch (xhr.readyState) {case 0:console.log("未初始化,尚未调用open()方法");breakcase 1:console.log("已初始化,调用了open()方法,但还未调用send()方法");breakcase 2:console.log("已发送,调用了send()方法,但还未收到服务端响应");breakcase 3:console.log("已接收,已经收到了部分服务端响应数据");breakdefault:console.log("已完成,已经收到了全部服务端响应数据");if (xhr.statusText === "OK") {console.log("请求成功");console.log(xhr.status);console.log(xhr.statusText);console.log(xhr.responseText);} else {console.log("请求失败");console.log(xhr.status);console.log(xhr.statusText);console.log(xhr.responseText);}}})// 请求方式,请求地址与参数,是否开启异步提交  提交的数据格式为url编码xhr.open("GET", "http://localhost:5700/get?username=Jack&userage=18", true);// 设置请求头,提交的数据格式为url编码xhr.setRequestHeader(\'Content-Type\', \'application/x-www-form-urlencoded; charset-UTF-8\');xhr.setRequestHeader(\'user_head\', \'HELLO WORLD\');// 发送请求xhr.send(null);

POST请求

发送POST请求:

"use strict";let xhr = new XMLHttpRequest();// 绑定回调函数xhr.addEventListener("readystatechange", () => {switch (xhr.readyState) {case 0:console.log("未初始化,尚未调用open()方法");breakcase 1:console.log("已初始化,调用了open()方法,但还未调用send()方法");breakcase 2:console.log("已发送,调用了send()方法,但还未收到服务端响应");breakcase 3:console.log("已接收,已经收到了部分服务端响应数据");breakdefault:console.log("已完成,已经收到了全部服务端响应数据");if (xhr.statusText === "OK") {console.log("请求成功");console.log(xhr.status);console.log(xhr.statusText);console.log(xhr.responseText);} else {console.log("请求失败");console.log(xhr.status);console.log(xhr.statusText);console.log(xhr.responseText);}}})// 请求方式,请求地址与参数,是否开启异步提交xhr.open("POST", "http://localhost:5700/post", true);// 设置请求头,提交的数据格式为url编码xhr.setRequestHeader(\'Content-Type\', \'application/x-www-form-urlencoded; charset-UTF-8\');xhr.setRequestHeader(\'user_head\', \'HELLO WORLD\');// 发送请求,提交的数据格式为url编码xhr.send("username=Jack&userage=18");

JSON格式

JSON格式的数据只能由POST请求发起,并且contentType应设置为appliction/json。

示例如下:

"use strict";let xhr = new XMLHttpRequest();// 绑定回调函数xhr.addEventListener("readystatechange", () => {switch (xhr.readyState) {case 0:console.log("未初始化,尚未调用open()方法");breakcase 1:console.log("已初始化,调用了open()方法,但还未调用send()方法");breakcase 2:console.log("已发送,调用了send()方法,但还未收到服务端响应");breakcase 3:console.log("已接收,已经收到了部分服务端响应数据");breakdefault:console.log("已完成,已经收到了全部服务端响应数据");if (xhr.statusText === "OK") {console.log("请求成功");console.log(xhr.status);console.log(xhr.statusText);console.log(xhr.responseText);} else {console.log("请求失败");console.log(xhr.status);console.log(xhr.statusText);console.log(xhr.responseText);}}})// 请求方式,请求地址与参数,是否开启异步提交xhr.open("POST", "http://localhost:5700/json", true);// 设置请求头xhr.setRequestHeader(\'Content-Type\', \'application/json\');xhr.setRequestHeader(\'user_head\', \'HELLO WORLD\');// 发送请求xhr.send(JSON.stringify({ "k1": "v1", "k2": "v2" }));

了解jQuery.ajax的原理

实现代码

原生的XmlHttpRequest所提供的方法太过于底层,因此我们可以对其进行封装。

这里以jQuery的Ajax为蓝本,实现一个类似功能的小组件,也是为了方便后期更加了解jQuery.Ajax()做准备。

我们准备实现的功能:

  • 实现发送GET请求
  • 实现发送POST请求
  • 实现更加方便的添加请求头
  • 实现发送JSON格式的请求数据
  • 实现自动反序列化JSON格式的响应数据
  • 实现文件上传

实现如下:

"use strict";class Ajax {constructor({ url, contentType, headers, data, beforeSend, dataFilter, success, error, complete, dataType = "", processData = true, type, method = type, traditional = false }) {// url:发送请求的地址,String类型// type:发送请求的方式,String类型,它和method都可以使用// method:发送请求的方式,String类型,它和type都可以使用// contentType:数据编码格式,相当于form表单的enctype,String类型// headers:设置的请求头,Object类型// dataType:接收的响应数据类型,如果是json则自动进行反序列化,String类型// data:发送的数据,post请求方式发送在请求体内,get请求发送会将其添加在url后,Object类型// processData:如果为true,浏览器将采用application/x-www-form-urlencoded方式对数据进行编码,如果为false则按照传入的contentType为准,bool类型// traditional:如果前端传递的是一个Array,如{"k1":[1,2,3,4]}则需要添加一个属性traditional:true,否则后端将接收不到该参数。(实际上接受的时候要使用request.POST.get("k1[]"))来进行接受,这是有问题的this.xhr = new XMLHttpRequest();this.url = url;this.type = (type || method).toUpperCase();this.method = method.toUpperCase();this.headers = headers;this.contentType = processData && !contentType ? "application/x-www-form-urlencoded" : contentType;this.data = data;this.dataType = dataType.toLowerCase();this.traditional = traditional;// beforeSend 在发送请求之前调用,并且传入一个XMLHttpRequest作为参数。// dataFilter 在请求成功之后调用。传入返回的数据以及"dataType"参数的值。并且必须返回新的数据(可能是处理过的)传递给success回调函数,也就是说它会在success与error之前调用// success 在请求成功之后调用。传入返回后的数据,以及包含成功代码的字符串// error 在请求出错时调用。传入XMLHttpRequest对象,描述错误类型的字符串以及一个异常对象(如果有的话)// complete 当请求完成之后调用这个函数,无论成功或失败。传入XMLHttpRequest对象,以及一个包含成功或错误代码的字符串this.beforeSend = beforeSend || function (xhr) { };// 该函数默认会自动的根据dataType对象responseText进行解码this.dataFilter = dataFilter || function (responseText, dataType) {switch (dataType) {case "application/json": case "json":// 新增,this.xhr.responseJSON属性this.xhr.responseJSON = JSON.parse(responseText);return this.xhr.responseJSON;default:return responseText;}};this.success = success || function (responseText, statusText) { };this.error = error || function (responseText, statusText) { };this.complete = complete || function (xhr, statusText) { };// 绑定回调函数this.bindStateChangeEvent();// 设置发送的数据并发送this.setRequestData();// 设置发送方式this.setXhrOpen();// 设置请求头this.setRequestHeader();// 发送请求this.sendRequest();}bindStateChangeEvent() {let resultText = "";let statusText = "";// 绑定回调函数,这里采用匿名函数使this指向Object,否则this将指向xhrthis.xhr.addEventListener("readystatechange", () => {switch (this.xhr.readyState) {case 1:this.beforeSend(this.xhr);breakcase 4:resultText = this.dataFilter(this.xhr.responseText, this.dataType || this.xhr.getResponseHeader("Content-Type").toLowerCase());if (this.xhr.statusText === "OK") {statusText = "success";this.success(resultText, statusText);} else {statusText = "error";this.error(this.xhr, "error");}this.complete(this.xhr, statusText);break}});}setRequestData() {// 判断是否要进行url编码,有2种情况:// 1.contentType是application/x-www-form-urlencoded时需要url编码// 2.传入的对象不是serialize()方法已经序列化好后的对象时不需要url编码if (this.contentType === "application/x-www-form-urlencoded" && !Object.isFrozen(this.data)) {this.data = this.urlEncode(this.data);}}urlEncode() {return Object.entries(this.data).reduce((prev, cur, index, array) => {// keylet key = cur[0];// value:2种情况,如果value是普通字符串,则直接进行encodeURIComponent编码处理,如果是数组将按照 k1=v1&k2=v2 的方式进行编码,并且判断是否传入traditionallet value = this.checkValueIsArray(cur);if (array.length - 1 === index) {// 判断是否是最后一位,如果是最后一位就加上&// traditional:如果前端传递的是一个Array,如{"k1":[1,2,3,4]}则需要添加一个属性traditional:true,否则后端将接收不到该参数。(实际上接受的时候要使用request.POST.get("k1[]"))来进行接受,这是有问题的return !this.traditional && cur[1] instanceof Array ? prev += `${key}[]=${value}` : prev += `${key}=${value}`;} else {return !this.traditional && cur[1] instanceof Array ? prev += `${key}[]=${value}&` : prev += `${key}=${value}&`;}}, "");}checkValueIsArray(cur) {if (cur[1] instanceof Array) {cur[1].forEach((value, index, array) => {if (index != array.length - 1) {value = encodeURIComponent(value);array[index] = value + "&";} else {array[index] = String(value);}})// traditional:如果前端传递的是一个Array,如{"k1":[1,2,3,4]}则需要添加一个属性traditional:true,否则后端将接收不到该参数。(实际上接受的时候要使用request.POST.get("k1[]"))来进行接受,这是有问题的,这里主要对数组中的第2个元素开始及其之后的所有元素进行url编码格式转换return this.traditional ? cur[1].join(`${cur[0]}=`) : cur[1].join(`${cur[0]}[]=`)}else {return encodeURIComponent(cur[1])}}setXhrOpen() {// 如果请求方式是GET请求,则在url后加上编码后的data,否则将只传递this.url// true参数为开启异步调用,也是默认的选项this.xhr.open(this.method,this.method === "GET" ? this.url.concat("?", this.data) : this.url,true);}setRequestHeader() {// 在不上传文件的时候,请求头Content-Type是必须的for (let [k, v] of Object.entries(this.headers)) {this.xhr.setRequestHeader(k, v);}if (this.contentType) {this.xhr.setRequestHeader("Content-Type", this.contentType);}}sendRequest() {// 发送请求时,如果请求方式为GET将使用this.xhr.send(null),否则将使用this.xhr.send(this.data)this.xhr.send(this.method === "GET" ? null : this.data);}}function getAjax(ajaxSettings) {return new Ajax(ajaxSettings);}function serialize(selector) {// 整体思路:先获取一个包含所有表单项对象,再将对象进行url编码let formNode = document.querySelector(selector);let haveValueNodeObject = {};Array.prototype.forEach.call(formNode.elements, (element, index, lst) => {switch (true) {// 多选或者单选select都将组成列表case element.tagName === "SELECT":Array.prototype.forEach.call(element.options, (option, index, array) => {if (option.selected) {haveValueNodeObject[element.name] ? haveValueNodeObject[element.name].push(option.value) : haveValueNodeObject[element.name] = [option.value];}})break// 多选,组成列表case element.type === "checkbox":if (element.checked) {haveValueNodeObject[element.name] ? haveValueNodeObject[element.name].push(element.value) : haveValueNodeObject[element.name] = [element.value];}break// 单选case element.type === "radio":if (element.checked) {haveValueNodeObject[element.name] = element.value}break// 其他的项目,注意文件对象不获取default:if (element.name && element.type !== "file") {haveValueNodeObject[element.name] = element.value || "";}}})// 冻结对象,代表已经经过序列化了,在发送数据时已避免url二次编码// 这里是传入一个对象并且继承Ajax的原型对象,因为这样做才能在编码时使用checkValueIsArray方法return Object.freeze(Ajax.prototype.urlEncode.call({ data: haveValueNodeObject, traditional: true, __proto__: Ajax.prototype },));}function serializeArray(selector) {// 提取form表单中的数据,并将其构建为一个name:value的数组 [{name:value}, {name:value}, {name:value}]let formNode = document.querySelector(selector);let haveValueArray = [];Array.prototype.forEach.call(formNode.elements, (element, index, lst) => {switch (true) {case element.tagName === "SELECT":Array.prototype.forEach.call(element.options, (option, index, array) => {if (option.selected) {haveValueArray.push({ "name": element.name, "value": option.value });}})breakcase element.type === "checkbox" || element.type === "radio":if (element.checked) {haveValueArray.push({ "name": element.name, "value": element.value });}breakdefault:if (element.name && element.type !== "file") {haveValueArray.push({ "name": element.name, "value": element.value });}}})return haveValueArray;}window.$ = { ajax: getAjax, serialize, serializeArray };

支持的上传格式

由于我们JavaScript的原生Ajax高度按照jQuery.ajax作为蓝本。所以常见的特性要与其保持一致。

如支持的原生上传数据格式实现:

  • 仅支持上传k-v的对象,不支持上传数组
  • 前端上传的数据中,不允许出现对象嵌套的形式。如{"k1":{"k1-1":v1}},这样只会得到{“k1” : “object”}
  • 如果前端传递的是一个Array,如 {"k1":[1, 2, 3, 4]} 则需要添加一个属性 traditional:true,否则后端将接收不到该参数。(实际上接受的时候要使用request.POST.get("k1[]"))来进行接受,这是有问题的

如果你上传的数据是json格式,当然就不会出现这些问题了。

如何发送GET请求

发送GET请求示例如下:

// 发送GET请求$.ajax({url: "http://localhost:5700/get",method: "get",headers: {"user_head": "Hello World",},data: { "name": "Jack", "age": 18 },dataType: "json",success: (responseText, statusText) => {console.log(responseText);console.log(statusText);},error: (responseText, statusText) => {console.log(responseText);console.log(statusText);},complete: (xhr, statusText) => {console.log("此处可获取响应头");}})

如何发送POST请求

发送POST请求示例如下:

// 发送post请求$.ajax({url: "http://localhost:5700/post",method: "post",headers: {"user_head": "Hello World",},data: { "name": "Jack", "age": 18 },dataType: "json",success: (responseText, statusText) => {console.log(responseText);console.log(statusText);},error: (responseText, statusText) => {console.log(responseText);console.log(statusText);},complete: (xhr, statusText) => {console.log("此处可获取响应头");}})

如何发送JSON数据

发送JSON格式数据示例如下:

// 发送json格式数据$.ajax({url: "http://localhost:5700/json",method: "post",headers: {"user_head": "Hello World",},data: JSON.stringify({ "name": "Jack", "age": 18 }),    // 1.手动进行JSON格式化dataType: "json",contentType: "application/json",                        // 2.请求头中声明本次发送的是JSON格式数据success: (responseText, statusText) => {console.log(responseText);console.log(statusText);},error: (responseText, statusText) => {console.log(responseText);console.log(statusText);},complete: (xhr, statusText) => {console.log("此处可获取响应头");}})

如何提交form表单的数据

针对form表单提交的数据,我们可以使用封装好的2个函数serialize()和serializeArray()。

  • serialize():提取form表单中的数据项,并对其做url编码处理,返回一个字符串,注意,它不会提取文件选择框

  • serializeArray():提取form表单中的数据,并将其构建为一个name:value的数组,注意,它不会提取文件选择框,最终格式为 [, , ],

示例如下,如果是serialize()则直接提交即可:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><form action="#" id="register"><div><label for="username">用户名</label><input type="text" id="username" name="username" required></div><div><label for="password">密码</label><input type="password" id="password" name="password" required></div><div><label for="male">男</label><input type="radio" name="gender" value="male" id="male" required><label for="female">女</label><input type="radio" name="gender" value="female" id="female"></div><div><label for="basketball">篮球</label><input type="checkbox" name="hobby" value="basketball" id="basketball" required><label for="football">足球</label><input type="checkbox" name="hobby" value="football" id="football"><label for="volleyball">排球</label><input type="checkbox" name="hobby" value="volleyball" id="volleyball"></div><div><label for="city">城市</label><select name="city" id="city" multiple><option value="beijing">北京</option><option value="shanghai">上海</option><option value="shenzhen">深圳</option></select></div><div><label for="avatar">上传头像</label><input type="file" name="avatar" id="avatar"></div><div><button type="button">提交</button></div></form></body><script src="./demo.js"></script><script>document.querySelector("button").addEventListener("click", (event) => {$.ajax({url: "http://localhost:5700/post",method: "post",headers: {"user_head": "Hello World",},data: $.serialize("#register"),dataType: "json",success: (responseText, statusText) => {console.log(responseText);console.log(statusText);},error: (responseText, statusText) => {console.log(responseText);console.log(statusText);},complete: (xhr, statusText) => {console.log("此处可获取响应头");}})console.log($.serialize("#register"));// username=%E4%BA%91%E5%B4%96&password=123&gender=male&hobby=basketball&hobby=football&city=shanghai&city=shenzhen})</script></html>

如果是serializeArray(),需要使用appliction/json的方式进行提交,因为该方法返回的是一个数组:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><form action="#" id="register"><div><label for="username">用户名</label><input type="text" id="username" name="username" required></div><div><label for="password">密码</label><input type="password" id="password" name="password" required></div><div><label for="male">男</label><input type="radio" name="gender" value="male" id="male" required><label for="female">女</label><input type="radio" name="gender" value="female" id="female"></div><div><label for="basketball">篮球</label><input type="checkbox" name="hobby" value="basketball" id="basketball" required><label for="football">足球</label><input type="checkbox" name="hobby" value="football" id="football"><label for="volleyball">排球</label><input type="checkbox" name="hobby" value="volleyball" id="volleyball"></div><div><label for="city">城市</label><select name="city" id="city" multiple><option value="beijing">北京</option><option value="shanghai">上海</option><option value="shenzhen">深圳</option></select></div><div><label for="avatar">上传头像</label><input type="file" name="avatar" id="avatar"></div><div><button type="button">提交</button></div></form></body><script src="./demo.js"></script><script>document.querySelector("button").addEventListener("click", (event) => {$.ajax({url: "http://localhost:5700/json",method: "post",headers: {"user_head": "Hello World",},data: JSON.stringify($.serializeArray("#register")),    // 1.手动进行JSON格式化dataType: "json",contentType: "application/json",                        // 2.请求头中声明本次发送的是JSON格式数据success: (responseText, statusText) => {console.log(responseText);console.log(statusText);},error: (responseText, statusText) => {console.log(responseText);console.log(statusText);},complete: (xhr, statusText) => {console.log("此处可获取响应头");}})console.log($.serializeArray("#register"));// Array(7)// 0: {username: "云崖"}// 1: {password: "123"}// 2: {gender: "male"}// 3: {hobby: "basketball"}// 4: {hobby: "football"}// 5: {city: "shanghai"}// 6: {city: "shenzhen"}})</script></html>

如何进行文件上传

如果要发送文件,我们需要借助FormData对象进行数据提交,以下是注意事项。

  • 在<form>表单中上传文件,必须要将enctype设置为multipart/form-data。

  • 但是在使用XmlHttpRequest对象上传文件时,并不需要指定 contentType为multipart/form-data 格式,所以不添加contentType请求头。

  • contentType应设置为false,即不使用任何数据格式,不使用任何编码

  • processData应设置为false,不让浏览器做任何数据格式的编码

示例如下,我们使用FormData搭配serializeArray()方法实现一个真正意义上的异步提交表单:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><form action="#" id="register"><div><label for="username">用户名</label><input type="text" id="username" name="username" required></div><div><label for="password">密码</label><input type="password" id="password" name="password" required></div><div><label for="male">男</label><input type="radio" name="gender" value="male" id="male" required><label for="female">女</label><input type="radio" name="gender" value="female" id="female"></div><div><label for="basketball">篮球</label><input type="checkbox" name="hobby" value="basketball" id="basketball" required><label for="football">足球</label><input type="checkbox" name="hobby" value="football" id="football"><label for="volleyball">排球</label><input type="checkbox" name="hobby" value="volleyball" id="volleyball"></div><div><label for="city">城市</label><select name="city" id="city" multiple><option value="beijing">北京</option><option value="shanghai">上海</option><option value="shenzhen">深圳</option></select></div><div><label for="avatar">上传头像</label><input type="file" name="avatar" id="avatar"></div><div><button type="button">提交</button></div></form></body><script src="./demo.js"></script><script>document.querySelector("button").addEventListener("click", (event) => {// 获取上传的文件对象let fileNode = document.querySelector("#avatar");let fileObj = fileNode.files[0];// 使用FormData用于伪造form表单提交的数据let fd = new FormData();// 添加文件fd.append(fileNode.name, fileObj);// 添加其他表单项$.serializeArray("#register").forEach((obj, index, array) => {fd.append(obj.name, obj.value);});// 发送json格式数据$.ajax({url: "http://localhost:5700/file",method: "post",headers: {"user_head": "Hello World",},data: fd,            // 直接发送ForData对象即可dataType: "json",contentType: false,  // 必须设置为falseprocessData: false,  // 必须设置为falsesuccess: (responseText, statusText) => {console.log(responseText);console.log(statusText);},error: (xhr, statusText) => {console.log(xhr.responseText);console.log(statusText);},complete: (xhr, statusText) => {console.log(statusText);}})})</script></html>
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 根据JavaScript中原生的XMLHttpRequest实现jQuery的Ajax