JavaScript:网络请求与前端通信

第十阶段:网络请求与前端通信

  1. XMLHttpRequest(简称 XHR)原生 AJAX

    AJAX :Asynchronous JavaScript And XML

    异步 JS 和 XML,作用:不刷新整个页面,局部更新数据

    现在主流传输格式是 JSON,XML 基本淘汰。

同步 / 异步请求、请求状态码 status、readyState:

  • 同步请求:请求会阻塞代码执行,直到请求完成。例如:
js 复制代码
let xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/api', false);
xhr.send();
if (xhr.status === 200) {
    console.log(xhr.responseText);
}
  • 异步请求 :请求不会阻塞代码执行,通过监听 readystatechange 事件获取请求状态。例如:
js 复制代码
let xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/api', true);
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(xhr.responseText);
    }
};
xhr.send();
  • 请求状态码 status :表示请求的结果,如 200 表示成功,404 表示未找到资源等。
  • readyState :表示请求的阶段,0 为未初始化,1 为已调用 open 方法,2 为已调用 send 方法,3 为请求中,4 为请求完成。

GET/POST 请求、请求头、请求参数、上传文件:

  • GET 请求:将参数附加在 URL 后面。例如:
js 复制代码
let xhr = new XMLHttpRequest();
let params = 'param1=value1&param2=value2';
xhr.open('GET', 'https://example.com/api?' + params, true);
xhr.send();
  • POST 请求:将参数放在请求体中。例如:
js 复制代码
let xhr = new XMLHttpRequest();
let params = 'param1=value1&param2=value2';
xhr.open('POST', 'https://example.com/api', true);
xhr.setRequestHeader('Content- type', 'application/x- www- form- urlencoded');
xhr.send(params);
  • 请求头 :使用 setRequestHeader 方法设置。例如设置 Content- type 头:
js 复制代码
xhr.setRequestHeader('Content- type', 'application/json');
  • 上传文件 :使用 FormData 对象。例如:
html 复制代码
<input type="file" id="fileInput">
<button id="uploadButton">上传</button>
<script>
    let uploadButton = document.getElementById('uploadButton');
    let fileInput = document.getElementById('fileInput');
    uploadButton.addEventListener('click', function () {
        let xhr = new XMLHttpRequest();
        let formData = new FormData();
        formData.append('file', fileInput.files[0]);
        xhr.open('POST', 'https://example.com/upload', true);
        xhr.send(formData);
    });
</script>
  1. Fetch API「ES6+」:

fetch 基础语法、Request/Response 对象:

  • 基础语法fetch 返回一个 Promise。例如:
js 复制代码
fetch('https://example.com/api')
  .then(response => response.json())
  .then(data => console.log(data));
  • Request 对象:可用于创建自定义请求。例如:
js 复制代码
let request = new Request('https://example.com/api', {
    method: 'GET',
    headers: {
        'Content- type': 'application/json'
    }
});
fetch(request)
  .then(response => response.json())
  .then(data => console.log(data));
  • Response 对象 :包含请求的响应。response.json() 用于解析 JSON 数据,response.text() 用于获取文本数据等。

Headers、GET/POST 传参、FormData:

  • Headers :可通过 headers 属性操作响应头。例如:
js 复制代码
fetch('https://example.com/api')
  .then(response => {
        console.log(response.headers.get('Content- type'));
        return response.json();
    })
  .then(data => console.log(data));
  • GET 传参:将参数拼接到 URL 上。例如:
js 复制代码
let params = new URLSearchParams();
params.append('param1', 'value1');
fetch('https://example.com/api?' + params.toString())
  .then(response => response.json())
  .then(data => console.log(data));
  • POST 传参 :使用 body 属性设置请求体。例如:
js 复制代码
let data = { key: 'value' };
fetch('https://example.com/api', {
    method: 'POST',
    headers: {
        'Content- type': 'application/json'
    },
    body: JSON.stringify(data)
})
  .then(response => response.json())
  .then(data => console.log(data));
  • FormData:用于上传文件和表单数据。例如:
html 复制代码
<input type="file" id="fileInput">
<button id="uploadButton">上传</button>
<script>
    let uploadButton = document.getElementById('uploadButton');
    let fileInput = document.getElementById('fileInput');
    uploadButton.addEventListener('click', function () {
        let formData = new FormData();
        formData.append('file', fileInput.files[0]);
        fetch('https://example.com/upload', {
            method: 'POST',
            body: formData
        })
          .then(response => response.text())
          .then(data => console.log(data));
    });
</script>

fetch 坑:4xx/5xx 不会触发 reject、跨域处理:

  • 4xx/5xx 不会触发 rejectfetch 只有在网络错误或请求被阻止时才会 reject,4xx 和 5xx 状态码不会。需要手动检查 response.ok。例如:
js 复制代码
fetch('https://example.com/api')
  .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json();
    })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
  • 跨域处理 :与 XMLHttpRequest 类似,通常通过 CORS 解决。服务端设置允许的源等响应头,前端无需特殊配置。
  1. 跨域问题详解:
  • 同源策略定义 :同源策略是浏览器的安全策略,要求协议、域名、端口都相同,否则视为跨域。例如,http://example.com:8080http://example.com:8081 不同源。
  • CORS 跨域资源共享(服务端配置) :服务端通过设置响应头允许跨域。例如在 Node.js 中使用 express- cors 中间件:
js 复制代码
const express = require('express');
const cors = require('express- cors');
const app = express();
app.use(cors());
// 其他路由和处理
  • JSONP 跨域原理 :利用 <script> 标签没有跨域限制的特点。前端创建一个 <script> 标签,设置其 src 属性为跨域接口,并指定一个回调函数名。服务端返回包含该回调函数调用及数据的 JavaScript 代码。例如:
html 复制代码
<script>
    function handleResponse(data) {
        console.log(data);
    }
</script>
<script src="https://example.com/api?callback = handleResponse"></script>

代理服务器、iframe 跨域、postMessage「ES6+」:

  • 代理服务器:前端请求本地代理服务器,代理服务器再请求跨域资源,然后将响应返回给前端,避免直接跨域。
  • iframe 跨域 :通过在主页面嵌入一个与目标域同源的 iframe,主页面和 iframe 之间通过 postMessage 通信。例如:
html 复制代码
<!-- 主页面-->
<iframe id="iframe" src="http://same- origin- domain.com/iframe.html"></iframe>
<script>
    window.addEventListener('message', function (event) {
        if (event.origin === 'http://same- origin- domain.com') {
            console.log('收到来自 iframe 的消息:', event.data);
        }
    });
    document.getElementById('iframe').contentWindow.postMessage('来自主页面的消息', 'http://same- origin- domain.com');
</script>
html 复制代码
<!-- iframe.html-->
<script>
    window.addEventListener('message', function (event) {
        if (event.origin === 'http://parent- domain.com') {
            console.log('收到来自主页面的消息:', event.data);
            window.parent.postMessage('来自 iframe 的回复', 'http://parent- domain.com');
        }
    });
</script>
  • postMessage「ES6+」 :可用于窗口之间的跨域通信,如 window.postMessage(data, targetOrigin)
  1. WebSocket「ES6+」长连接实时通信:
  • 是什么:WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,允许服务器主动向客户端推送数据。例如:
js 复制代码
let socket = new WebSocket('ws://example.com/socket');
socket.onopen = function () {
    console.log('连接已建立');
    socket.send('Hello, server!');
};
socket.onmessage = function (event) {
    console.log('收到消息:', event.data);
};
socket.onclose = function () {
    console.log('连接已关闭');
};
  • 为什么:传统的 HTTP 是请求- 响应模式,服务器不能主动推送数据。WebSocket 适用于实时通信场景,如聊天应用、实时数据更新等。
  • 怎么用 :创建 WebSocket 实例,监听 open(连接建立)、message(收到消息)、close(连接关闭)等事件,使用 send 方法发送数据。
  1. 简单文件上传、下载前端实现:
  • 文件上传 :已在 XMLHttpRequest 和 Fetch API 部分介绍,通过 FormData 对象实现。
  • 文件下载 :可以创建一个 <a> 标签,设置其 href 属性为文件的 URL,并设置 download 属性指定下载文件名。例如:
html 复制代码
<button id="downloadButton">下载文件</button>
<script>
    let downloadButton = document.getElementById('downloadButton');
    downloadButton.addEventListener('click', function () {
        let a = document.createElement('a');
        a.href = 'https://example.com/file.pdf';
        a.download = 'example.pdf';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    });
</script>

实战练习:

  1. fetch 发送表单 FormData 上传数据
  2. JSONP 简易跨域封装
  3. WebSocket 简易聊天室收发消息

思考题:

  1. fetch 为什么 4xx/5xx 不会进入 catch?
  2. 同源策略限制哪些操作?
  3. WebSocket 和 AJAX 轮询区别?
相关推荐
明月_清风1 小时前
从概念到代码:用 Ontology 构建你的第一个知识图谱
前端·后端
程序员黑豆2 小时前
鸿蒙应用开发:AppStorage 全局状态存储用法教程
前端·harmonyos
猫猫不是喵喵.2 小时前
Vue3 中 computed 计算属性与 watch、watchEffect 监听
前端·javascript·vue.js
techdashen2 小时前
Go设计取舍之三: 0.3ns每次的错误Benchmark
开发语言·后端·golang
rosmis2 小时前
agent各指标定义
android·java·开发语言
En^_^Joy2 小时前
Vue项目创建与入口配置全攻略
前端·vue.js·arcgis
mifengxing2 小时前
Java 集合进阶(一)
java·开发语言·数据结构·复习笔记
孪生质数-2 小时前
AI Agent 工程实践(一):大模型 API 接入示范
网络·人工智能·ai·chatgpt·github·claude·claudecode