网站

Fetch API | MDN

XMLHttpRequest | MDN

HTTP 请求方法 | MDN

引入

网页需要和服务器交换数据:获取用户信息、提交表单、加载列表等。

JS 提供了两种发送网络请求的方式:早期的 XMLHttpRequest 和现代的 fetch()

正文

定义

定义

网络请求是 JS 向服务器发送 HTTP 请求,获取数据或提交数据的过程。常用 XMLHttpRequest(旧)和 fetch()(新)两种方式。

HTTP 请求方法

方法用途特点
GET获取数据参数拼在 URL 上
POST提交数据参数放在请求体中
PUT更新数据(全量)替换整个资源
DELETE删除数据删除指定资源
PATCH更新数据(部分)只更新部分字段

最常用的是 GETPOST

fetch() 基础用法

fetch() 是现代浏览器推荐的请求方式。

GET 请求

fetch("https://api.example.com/users")
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    console.log(data);
  });

默认就是 GET 请求,只需要传入 URL 即可。

POST 请求

fetch("https://api.example.com/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "张三",
    age: 25
  })
})
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    console.log(data);
  });

POST 请求需要配置 methodheadersbody

fetch() 的第二个参数

配置项作用示例
method请求方法"GET""POST"
headers请求头{ "Content-Type": "application/json" }
body请求体JSON.stringify(data)

响应处理

fetch() 返回一个 Promise,.then() 里拿到的 response 对象不是最终数据,需要进一步解析。

方法作用
response.json()解析为 JSON 对象
response.text()解析为纯文本
response.blob()解析为二进制数据(文件、图片)
response.statusHTTP 状态码
response.ok状态码是否在 200-299 范围
response.headers响应头
fetch("https://api.example.com/users")
  .then(function (response) {
    console.log("状态码:" + response.status);
    return response.json();
  })
  .then(function (data) {
    console.log("数据:", data);
  });

错误处理

fetch() 只有在网络故障时才会触发 .catch(),HTTP 错误(404、500)不会自动报错。

fetch("https://api.example.com/users")
  .then(function (response) {
    if (!response.ok) {
      throw new Error("HTTP 错误:" + response.status);
    }
    return response.json();
  })
  .then(function (data) {
    console.log(data);
  })
  .catch(function (error) {
    console.log("请求失败:" + error.message);
  });

带查询参数的 GET 请求

const keyword = "js";
const page = 1;
 
fetch("https://api.example.com/search?q=" + keyword + "&page=" + page)
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    console.log(data);
  });

也可以用 URLSearchParams 来构建查询参数:

const params = new URLSearchParams({
  q: "js",
  page: 1
});
 
fetch("https://api.example.com/search?" + params)
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    console.log(data);
  });

XMLHttpRequest 基础用法

XMLHttpRequest(简称 XHR)是早期的请求方式,了解它有助于阅读旧代码。

GET 请求

const xhr = new XMLHttpRequest();
 
xhr.open("GET", "https://api.example.com/users");
 
xhr.onload = function () {
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.responseText);
    console.log(data);
  }
};
 
xhr.onerror = function () {
  console.log("请求失败");
};
 
xhr.send();

POST 请求

const xhr = new XMLHttpRequest();
 
xhr.open("POST", "https://api.example.com/users");
xhr.setRequestHeader("Content-Type", "application/json");
 
xhr.onload = function () {
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.responseText);
    console.log(data);
  }
};
 
xhr.send(JSON.stringify({
  name: "张三",
  age: 25
}));

XHR 和 fetch 对比

对比XMLHttpRequestfetch()
写法繁琐,回调多简洁,基于 Promise
错误处理onerror.catch()
HTTP 错误status 判断也需要手动判断
中止请求xhr.abort()AbortController
上传进度支持不支持
兼容性所有浏览器IE 不支持

例子

加载并渲染列表

<button id="loadBtn">加载</button>
<ul id="list"></ul>
<p id="loading" style="display: none;">加载中...</p>
const loadBtn = document.querySelector("#loadBtn");
const list = document.querySelector("#list");
const loading = document.querySelector("#loading");
 
loadBtn.addEventListener("click", function () {
  loading.style.display = "block";
  list.innerHTML = "";
 
  fetch("https://api.example.com/items")
    .then(function (response) {
      if (!response.ok) {
        throw new Error("加载失败");
      }
      return response.json();
    })
    .then(function (items) {
      items.forEach(function (item) {
        const li = document.createElement("li");
        li.textContent = item.name;
        list.appendChild(li);
      });
    })
    .catch(function (error) {
      console.log(error.message);
    })
    .finally(function () {
      loading.style.display = "none";
    });
});

提交表单数据

<form id="form">
  <input name="title" type="text" placeholder="标题">
  <textarea name="content" placeholder="内容"></textarea>
  <button type="submit">发布</button>
</form>
const form = document.querySelector("#form");
 
form.addEventListener("submit", function (event) {
  event.preventDefault();
 
  const title = form.querySelector("[name='title']").value;
  const content = form.querySelector("[name='content']").value;
 
  if (title === "" || content === "") {
    return;
  }
 
  fetch("https://api.example.com/posts", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ title: title, content: content })
  })
    .then(function (response) {
      return response.json();
    })
    .then(function (data) {
      console.log("发布成功:", data);
      form.reset();
    });
});

form.reset() 会清空表单所有输入框的内容。

常见写法

写法作用
fetch(url)发送 GET 请求
fetch(url, { method: "POST", body: … })发送 POST 请求
response.json()解析 JSON 响应
response.text()解析纯文本响应
.then(fn).catch(fn)处理成功和错误
JSON.stringify(data)把对象转为 JSON 字符串
JSON.parse(text)把 JSON 字符串转为对象

特点

  • fetch() 写法简洁,基于 Promise,是现代推荐的请求方式
  • XMLHttpRequest 是旧写法,但兼容性好,有些老项目还在用
  • GET 用于获取数据,参数在 URL 上
  • POST 用于提交数据,参数在请求体中
  • response.json() 解析 JSON 数据,response.text() 解析纯文本
  • HTTP 错误状态码不会触发 .catch(),需要手动检查 response.ok
  • .finally() 无论成功或失败都会执行,适合隐藏加载提示

注意事项

  • fetch() 是异步的,不能直接用 const data = fetch(url) 获取数据
  • 跨域请求需要服务器配置 CORS
  • POST 请求发送 JSON 数据时,必须设置 Content-Type: application/json
  • JSON.stringify() 把 JS 对象转成字符串,JSON.parse() 把字符串转回对象
  • 请求可能需要一段时间,期间应该给用户展示”加载中”的提示
  • 网络请求可能失败,一定要处理错误情况

理解

可以把网络请求理解成”寄信”。

发请求就是写信寄出去,服务器收到信后回复。

fetch() 是现代快递,流程简单,写好地址(URL)、内容(body),寄出去后等回复。

XMLHttpRequest 是传统邮局,步骤多,但效果一样。

我理解网络请求的重点是:fetch() 发请求,用 .then() 处理回复,用 .catch() 处理异常

引出

掌握了网络请求的基础后,可以深入学习 JS Ajax,了解 Ajax 在实际项目中的应用场景。

网络请求是异步操作,理解 JS PromiseJS async await 可以让异步代码更容易读写。