1. XMLHttpRequest #

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/users', true);
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {   // 请求已完成,响应已准备好处理
    if (xhr.status === 200) {
      console.log(xhr.responseText);
    } else {
      console.error('Request failed. Returned status of ' + xhr.status);
    }
  }
};
xhr.send();

1.1 open #

xhr.open(method, url[, async])

1.2 onreadystatechange #

1.2.1 readyState #

状态 描述
0 UNSENT XMLHttpRequest 对象已创建,但尚未调用 open() 方法。
1 OPENED open() 方法已调用。
2 HEADERS_RECEIVED send() 方法已调用,并且头部和状态已经可获得。
3 LOADING 下载中,此时 responseText 属性已经包含部分数据。
4 DONE 下载操作已完成。

可以根据 readyState 的值来执行相应的操作。通常,在 readyState 的值为 4 时,会检查响应的状态码,以确定请求的结果。

1.2.2 status #

1.2.3 response #

属性名 用途
responseText 获取以字符串形式表示的服务器响应。
response 获取服务器的响应。该响应的类型取决于responseType的设置
responseType 设置或获取期望的响应类型(如''、'json'等)
responseXML 获取以DOM文档形式表示的服务器响应

1.3 send #

xhr.send([body]);

2. 发送请求 #

2.1 创建一个新用户(POST请求) #

let xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/users', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log(xhr.responseText);
  }
}
xhr.send(JSON.stringify({name: 'New User', age: 20}));

2.2 更新用户信息(PUT请求) #

let xhr = new XMLHttpRequest();
xhr.open('PUT', 'http://localhost:3000/users?id=1', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({name: 'Updated User', age: 21}));
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log(xhr.responseText);
  }
}

2.3 查询用户信息(GET请求) #

let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/users?id=1', true);
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log(xhr.responseText);
  }
}
xhr.send();

2.4 删除用户(DELETE请求) #

let xhr = new XMLHttpRequest();
xhr.open('DELETE', 'http://localhost:3000/users?id=1', true);
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log(xhr.responseText);
  }
}
xhr.send();

3. 服务器端倒计时功能 #

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>倒计时</title>
</head>
<body>
    <label for="datetime">选择日期和时间:</label>
    <input type="datetime-local" id="datetime">
    <div id="countdown"></div>
    <script>
        // 获取页面上的日期时间选择器元素
        let datetimePicker = document.getElementById('datetime');
        // 获取页面上的倒计时显示元素
        let countdownDisplay = document.getElementById('countdown')
        // 添加监听事件,当日期时间选择器的值发生变化时,创建新的倒计时
        datetimePicker.addEventListener('change', function (event) {
            // 从选择器获取新的目标日期
            const targetDate = new Date(event.target.value);
            // 创建新的倒计时,每秒更新一次
            setInterval(() => updateCountdown(targetDate), 1000);
        });
        // 定义倒计时更新函数
        function updateCountdown(targetDate) {
            // 创建新的XMLHttpRequest
            let xhr = new XMLHttpRequest();
            // 设置请求为HEAD方法,并指定URL
            xhr.open('HEAD', '/', true);
            // 当请求的状态发生变化时,执行此函数
            xhr.onreadystatechange = function () {
                // 当请求完成并且返回的状态码为200时
                if (xhr.readyState === 4 && xhr.status === 200) {
                    // 获取服务器返回的时间
                    let serverDate = new Date(xhr.getResponseHeader('Date'));
                    // 计算目标日期与服务器日期的时间差
                    let diff = targetDate - serverDate;
                    // 如果时间差大于0,也就是目标日期还没有到
                    if (diff > 0) {
                        // 计算剩余的秒、分钟、小时、日、月、年
                        let seconds = Math.floor((diff / 1000) % 60),
                            minutes = Math.floor((diff / (1000 * 60)) % 60),
                            hours = Math.floor((diff / (1000 * 60 * 60)) % 24),
                            days = Math.floor((diff / (1000 * 60 * 60 * 24)) % 30.44),
                            months = Math.floor((diff / (1000 * 60 * 60 * 24 * 30.44)) % 12),
                            years = Math.floor(diff / (1000 * 60 * 60 * 24 * 365));
                        // 更新倒计时显示元素的内容
                        let desc = '';
                        if (years > 0) {
                            desc += `${years}年`;
                        }
                        if (months > 0) {
                            desc += `${months}月`;
                        }
                        if (days > 0) {
                            desc += `${days}日`;
                        }
                        if (hours > 0) {
                            desc += `${hours}时`;
                        }
                        if (minutes > 0) {
                            desc += `${minutes}分`;
                        }
                        if (seconds > 0) {
                            desc += `${seconds}秒`;
                        }
                        countdownDisplay.innerHTML = `距离目标日期还有${desc}`;
                    }
                }
            }
            // 发送请求
            xhr.send();
        }
    </script>
</body>
</html>

4.编码和解码 #

JavaScript 中有关 URI (Uniform Resource Identifiers) 的编码和解码方法主要有以下四个:

  1. encodeURI(): 它将一个完整的URI进行编码。这个方法不会对 ASCII 字母和数字以及一些特殊字符:- _ . ! ~ * ' ( ) #进行编码。

    例子:

     var uri = "https://www.example.com/?name=小明&job=programmer";
     var encoded = encodeURI(uri);
     console.log(encoded);
     // 输出:https://www.example.com/?name=%E5%B0%8F%E6%98%8E&job=programmer
    
  2. decodeURI(): 是 encodeURI() 方法的逆操作,用于解码由 encodeURI() 方法编码的URI。

    例子:

     var uri = "https://www.example.com/?name=%E5%B0%8F%E6%98%8E&job=programmer";
     var decoded = decodeURI(uri);
     console.log(decoded);
     // 输出:https://www.example.com/?name=小明&job=programmer
    
  3. encodeURIComponent(): 这个方法将 URI 的组成部分进行编码,对所有非标准的 ASCII 字符进行编码。它将空格编码为 %20(而不是 encodeURI() 中的 + 符号)。除了 - _ . ! ~ * ' ( )之外,它会对其他所有字符进行编码。这个方法常用于编码查询字符串(或者说,URL的一部分)。

    例子:

     var queryParam = "name=小明&job=programmer";
     var encoded = encodeURIComponent(queryParam);
     console.log(encoded);
     // 输出:name%3D%E5%B0%8F%E5%8D%97%26job%3Dprogrammer
    
  4. decodeURIComponent(): 是 encodeURIComponent() 方法的

对应的解码函数,它可以解码由 encodeURIComponent() 方法编码的部分URI。

例子:

var queryParam = "name%3D%E5%B0%8F%E5%8D%97%26job%3D%E5%BC%80%E5%8F%91%E5%91%98";
var decoded = decodeURIComponent(queryParam);
console.log(decoded);
// 输出:name=小明&job=programmer

这四个方法可以帮助我们在处理 URI 时正确地对字符进行编码和解码,以避免由于字符的特殊性导致的问题。

例如,URL 不能包含某些字符,如空格。如果 URL 包含非法字符,就必须先进行编码。同时,有些字符在 URL 中有特殊的含义(如 #&),如果需要这些字符被视为文本字符,也必须进行编码。

反过来,当我们收到一个已编码的 URI 后,可以使用相应的解码函数对其进行解码,以获得原始的文本信息。