JavaScript HTTP与网络编程 | 自在学
HTTP 通信
在现代Web开发中,HTTP通信是构建动态交互式应用程序的核心技术。传统的Web页面每次用户操作都需要完整地重新加载页面,这种模式不仅用户体验较差,也会带来不必要的网络开销。而通过JavaScript进行HTTP通信,我们可以在不刷新页面的情况下与服务器进行数据交换,从而创建更加流畅和响应式的用户界面。
HTTP通信技术的发展催生了Ajax和Comet等重要的Web应用架构模式。Ajax允许客户端主动向服务器请求数据,而Comet则实现了服务器向客户端的主动推送。这些技术的应用使得Web应用程序具备了接近桌面应用程序的交互体验,同时保持了Web技术的跨平台特性和易于部署的优势。
Ajax基础概念
Ajax(Asynchronous JavaScript and XML)是一种用于创建快速动态网页的技术组合。尽管名称中包含XML,但现代Ajax应用更多使用JSON作为数据交换格式。Ajax的核心思想是利用JavaScript在后台与服务器进行异步通信,获取数据后动态更新页面的部分内容,而无需重新加载整个页面。
在Ajax出现之前,Web应用的交互模式相对简单:用户在页面上执行操作(如点击链接或提交表单),浏览器发送请求到服务器,服务器处理请求并返回一个全新的页面。这种模式的缺点是用户每次操作都要等待页面完全重新加载,交互体验相对较差。Ajax技术通过在后台进行HTTP通信,实现了页面的局部更新,大大提升了用户体验的流畅性。
Ajax的工作原理基于浏览器提供的XMLHttpRequest对象(或其现代化的替代方案)。当JavaScript代码需要获取服务器数据时,它会创建一个HTTP请求,指定请求的方法(GET、POST等)、URL和其他必要参数。服务器接收到请求后进行处理,并将结果以特定格式(如JSON、XML或纯文本)返回给客户端。JavaScript接收到响应后,解析数据并更新页面中的相应元素,从而实现了动态内容更新。
XMLHttpRequest
XMLHttpRequest是实现Ajax通信的核心API,它为JavaScript提供了完整的HTTP客户端功能。虽然名称中包含XML,但实际上它可以处理任何类型的文本数据,包括JSON、HTML、纯文本等格式。
现代浏览器都原生支持XMLHttpRequest,它已经成为Web开发中不可或缺的工具。
基本使用方法
使用XMLHttpRequest进行HTTP通信需要遵循特定的步骤。
首先创建XMLHttpRequest对象实例,然后配置请求参数,设置响应处理函数,最后发送请求。
这个过程虽然看起来相对复杂,但每个步骤都有其特定的作用和意义。
// 创建XMLHttpRequest对象
const request = new XMLHttpRequest ();
// 配置请求:方法为GET,目标URL为用户数据接口
request. open ( 'GET' , '/api/users' );
// 设置响应处理函数
request. onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200 ) {
const userData = JSON . parse (request.responseText);
console. log ( '用户数据:' , userData);
}
};
// 发送请求
request. send ();
用户数据: [{id: 1, name: "张三", email: "zhang@example.com"}]
XMLHttpRequest对象的生命周期通过readyState属性来表示,该属性的值从0到4分别代表不同的状态。状态0表示对象已创建但尚未调用open方法;
状态1表示已调用open方法但尚未发送请求;状态2表示已发送请求且接收到响应头;状态3表示正在接收响应体;状态4表示请求完成。在实际开发中,我们通常只关心状态4,即请求完成的状态。
处理不同类型的请求
HTTP协议支持多种请求方法,每种方法都有其特定的用途和语义。GET方法用于从服务器获取资源,通常不应该有副作用;POST方法用于向服务器提交数据,常用于表单提交和数据创建;PUT方法用于更新资源;DELETE方法用于删除资源。在Web应用开发中,GET和POST是最常用的两种方法。
GET请求通常用于数据查询和获取,由于GET请求不包含请求体,所有的参数都需要通过URL的查询字符串传递。这种方式的优点是简单直观,缺点是参数长度受到URL长度限制,且参数在URL中可见,不适合传递敏感信息。
// GET请求示例:获取指定用户的信息
function getUserInfo ( userId ) {
const request = new XMLHttpRequest ();
request. open ( 'GET' , `/api/users/${ userId }` );
request. onreadystatechange = function () {
if (request.readyState === 4 ) {
if (request.status === 200 ) {
const userInfo
POST请求则适合向服务器提交数据,如表单提交、文件上传、数据创建等操作。POST请求可以在请求体中携带大量数据,
且数据不会显示在URL中,相对更加安全。在发送POST请求时,通常需要设置适当的Content-Type头部来告知服务器请求体的数据格式。
// POST请求示例:创建新用户
function createUser ( userData ) {
const request = new XMLHttpRequest ();
request. open ( 'POST' , '/api/users' );
// 设置请求头,指定数据格式为JSON
request. setRequestHeader ( 'Content-Type' , 'application/json' );
request. onreadystatechange = function () {
if (request.readyState === 4
用户创建成功: {id: 2, name: "李四", email: "lisi@example.com", age: 25}
响应处理与错误管理
在实际的Web应用开发中,网络请求并不总是成功的。服务器可能返回错误状态码,网络连接可能中断,或者服务器可能返回格式不正确的数据。因此,健壮的HTTP通信代码必须包含完善的错误处理机制。
HTTP状态码是服务器向客户端传达请求处理结果的重要方式。200表示成功,400系列状态码表示客户端错误(如404表示资源未找到),500系列状态码表示服务器错误。在处理响应时,我们需要根据不同的状态码采取相应的处理策略。
// 完善的HTTP请求处理函数
function makeRequest ( method , url , data = null ) {
return new Promise (( resolve , reject ) => {
const request = new XMLHttpRequest ();
request. open (method, url);
// 设置超时时间
request.timeout = 10000 ; // 10秒超时
跨域请求与CORS
在Web安全架构中,同源策略是一个重要的安全机制,它限制了从一个源加载的文档或脚本访问另一个源的资源。同源策略要求协议、域名和端口都相同才被认为是同源。这个策略有效地防止了恶意网站访问其他网站的敏感数据,但同时也限制了合法的跨域通信需求。
现代Web应用经常需要与不同域的服务进行通信,比如调用第三方API、访问CDN资源或者实现微服务架构。为了在保证安全的前提下实现跨域通信,W3C制定了CORS(Cross-Origin Resource Sharing)标准。CORS允许服务器通过设置特定的HTTP头部来声明哪些外部域可以访问其资源。
当浏览器发现JavaScript代码尝试进行跨域请求时,它会自动在请求中添加Origin头部,告知服务器请求的来源。服务器收到请求后,可以通过检查Origin头部决定是否允许这个跨域请求。如果允许,服务器会在响应中包含Access-Control-Allow-Origin头部,浏览器接收到这个头部后才会将响应数据提供给JavaScript代码。
// 跨域请求示例
function fetchExternalData () {
const request = new XMLHttpRequest ();
request. open ( 'GET' , 'https://api.external-service.com/data' );
request. onreadystatechange = function () {
if (request.readyState === 4 ) {
if (request.status === 200 ) {
const data = JSON . parse
对于复杂的跨域请求(如包含自定义头部或使用PUT、DELETE等方法的请求),浏览器会先发送一个预检请求(OPTIONS方法)来询问服务器是否允许实际请求。只有当预检请求得到允许的响应后,浏览器才会发送实际的请求。这种机制确保了跨域通信的安全性。
JSONP技术
在CORS标准普及之前,JSONP(JSON with Padding)是实现跨域数据获取的主要技术手段。JSONP利用了script标签不受同源策略限制的特性,通过动态创建script元素来实现跨域数据请求。虽然现在CORS已经成为主流解决方案,但JSONP在某些特定场景下仍然有其价值,特别是需要支持较老版本浏览器的情况。
JSONP的工作原理是将数据请求伪装成脚本加载。服务器不直接返回JSON数据,而是返回一个JavaScript函数调用,这个函数的参数就是要传递的数据。客户端需要预先定义这个回调函数来处理返回的数据。当script标签加载完成后,返回的JavaScript代码会被执行,从而调用预定义的回调函数并传入数据。
// JSONP实现函数
function jsonpRequest ( url , callback ) {
// 生成唯一的回调函数名
const callbackName = 'jsonp_callback_' + Math. random (). toString ( 36 ). substr ( 2 , 9 );
// 在全局作用域创建回调函数
window[callbackName] = function ( data ) {
callback (data);
// 清理:删除回调函数和script元素
delete
天气数据: {city: "北京", temperature: 22, weather: "晴朗"}
JSONP技术的优点是兼容性好,几乎所有浏览器都支持script标签的跨域加载。但它也有明显的限制:只支持GET请求,存在安全风险(需要信任数据源),错误处理相对困难。在现代Web开发中,除非有特殊的兼容性要求,否则建议优先使用CORS方案。
现代化的Fetch API
随着JavaScript语言的发展,原生的Fetch API逐渐成为XMLHttpRequest的现代化替代方案。Fetch API提供了更简洁的语法和更好的Promise支持,使得异步HTTP通信的代码更加清晰和易于维护。Fetch API基于Promise设计,天然支持async/await语法,避免了回调函数嵌套的问题。
Fetch API的设计理念更加现代化,它将请求和响应抽象为独立的对象,提供了更好的流式处理能力和更灵活的配置选项。与XMLHttpRequest相比,Fetch的语法更加简洁,错误处理更加直观,代码的可读性和可维护性都有显著提升。
// 使用Fetch API进行GET请求
async function fetchUserData ( userId ) {
try {
const response = await fetch ( `/api/users/${ userId }` );
if ( ! response.ok) {
throw new Error ( `HTTP错误: ${ response . status }` );
}
const userData =
Fetch API还提供了丰富的配置选项,支持设置请求头、请求方法、请求体、超时时间等各种参数。它的响应对象也提供了多种数据解析方法,如json()、text()、blob()等,可以灵活处理不同类型的响应数据。
服务器推送与实时通信
传统的HTTP通信模式是客户端主动向服务器发起请求,服务器响应后连接关闭。但在某些应用场景中,我们需要服务器能够主动向客户端推送数据,如即时聊天、实时通知、股票行情更新等。为了实现这种服务器推送功能,Web技术发展出了多种解决方案。
Server-Sent Events
Server-Sent Events(SSE)是HTML5标准中定义的一种服务器向客户端推送数据的技术。SSE基于标准的HTTP连接,客户端通过EventSource对象与服务器建立持久连接,服务器可以通过这个连接持续向客户端发送数据。SSE的优点是实现简单,基于标准HTTP协议,不需要特殊的服务器配置。
// 创建EventSource连接
const eventSource = new EventSource ( '/api/notifications' );
// 监听消息事件
eventSource. onmessage = function ( event ) {
const notification = JSON . parse (event.data);
console. log ( '收到通知:' , notification);
displayNotification (notification);
};
// 监听连接打开事件
eventSource. onopen = function
WebSocket全双工通信
WebSocket是另一种重要的实时通信技术,它在客户端和服务器之间建立全双工的通信通道。与SSE只能服务器向客户端推送数据不同,WebSocket支持双向通信,客户端和服务器都可以随时向对方发送数据。WebSocket特别适合需要频繁双向交互的应用,如在线游戏、协作编辑、实时聊天等。
// 创建WebSocket连接
const socket = new WebSocket ( 'ws://localhost:8080/chat' );
// 连接打开时的处理
socket. onopen = function () {
console. log ( 'WebSocket连接已建立' );
// 发送登录消息
socket. send ( JSON . stringify ({
type: 'login' ,
username: '用户123'
}));
};
// 接收消息的处理
socket.
WebSocket连接已建立
收到消息: {type: "user_joined", username: "用户456"}
收到消息: {type: "chat", username: "用户456", text: "大家好!"}
HTTP通信的性能优化
在实际的Web应用开发中,HTTP通信的性能直接影响用户体验。优化HTTP通信性能需要从多个维度考虑,包括减少请求次数、优化请求大小、合理使用缓存、实现请求防抖和节流等技术手段。
请求合并与批处理
当应用需要获取多个相关的数据时,与其发送多个独立的请求,不如将这些请求合并成一个批处理请求。这样可以减少网络往返次数,降低HTTP头部开销,提高整体性能。
// 批处理请求管理器
class BatchRequestManager {
constructor ( endpoint , delay = 100 ) {
this .endpoint = endpoint;
this .delay = delay;
this .pendingRequests = [];
this .timeoutId = null ;
}
// 添加请求到批次中
addRequest ( data ) {
return new
请求缓存策略
合理的缓存策略可以显著减少不必要的网络请求,提高应用响应速度。可以实现内存缓存、基于时间的缓存失效、基于版本的缓存更新等机制。
// HTTP请求缓存管理器
class RequestCache {
constructor ( maxSize = 100 , defaultTTL = 300000 ) { // 5分钟默认TTL
this .cache = new Map ();
this .maxSize = maxSize;
this .defaultTTL = defaultTTL;
}
// 生成缓存键
generateKey ( url , options = {}) {
发送网络请求: /api/products
产品数据: [{id: 1, name: "产品A"}, {id: 2, name: "产品B"}]
从缓存返回数据: /api/products
缓存数据: [{id: 1, name: "产品A"}, {id: 2, name: "产品B"}]
习题
在JavaScript中,用于发送HTTP请求的核心对象是?
A. XMLHttpRequest
B. HttpRequest
C. AjaxRequest
D. WebRequest
XMLHttpRequest对象的readyState属性可能的值范围是?
A. 0,1,2,3,4
B. 1,2,3,4,5
C. 0,1,2,3
D. 1,2,3,4
A. 同源策略的限制
B. 性能问题
C. 语法复杂
D. 兼容性差
CORS机制中,服务器通过哪个HTTP头部来允许跨域请求?
A. Access-Control-Allow-Origin
B. Cross-Origin-Allow
C. Allow-Cross-Domain
D. Origin-Control
A. 只能客户端向服务器发送
B. 只能服务器向客户端推送
C. 支持双向通信
D. 只支持文本数据
创建一个简单的XMLHttpRequest请求示例,要求:
发送GET请求获取数据
处理请求成功和失败的情况
解析返回的JSON数据
// 创建XMLHttpRequest对象
const request = new XMLHttpRequest ();
// 配置GET请求到'/api/data'
request. open ( 'GET' , '/api/data' , true );
// 设置响应处理函数
request. onreadystatechange = function () {
if (request.readyState === 4 ) {
if (request.status === 200 ) {
// 请求成功,解析JSON数据
try {
使用Fetch API发送HTTP请求,要求:
发送GET请求获取数据
使用async/await处理异步操作
包含错误处理
// 使用Fetch API发送GET请求
async function fetchData () {
try {
const response = await fetch ( '/api/users' );
// 检查响应是否成功
if ( ! response.ok) {
throw new Error ( '请求失败,状态码: ' + response.status);
}
// 解析JSON数据
const data = await response. json
实现一个简单的HTTP请求工具函数,要求:
支持GET和POST请求
使用Promise处理异步操作
包含基本的错误处理
// 简单的HTTP请求工具函数
function httpRequest ( method , url , data ) {
return new Promise ( function ( resolve , reject ) {
const request = new XMLHttpRequest ();
// 配置请求
request. open (method, url, true );
// 如果是POST请求,设置请求头
if (method ===
=
JSON
.
parse
(request.responseText);
displayUserInfo (userInfo);
} else {
console. error ( '获取用户信息失败:' , request.statusText);
}
}
};
request. send ();
}
function displayUserInfo ( userInfo ) {
console. log ( `用户姓名: ${ userInfo . name }` );
console. log ( `用户邮箱: ${ userInfo . email }` );
}
) {
if (request.status === 201 ) {
const newUser = JSON . parse (request.responseText);
console. log ( '用户创建成功:' , newUser);
} else {
console. error ( '用户创建失败:' , request.statusText);
}
}
};
// 将JavaScript对象转换为JSON字符串发送
request. send ( JSON . stringify (userData));
}
// 使用示例
createUser ({
name: '李四' ,
email: 'lisi@example.com' ,
age: 25
});
// 如果是POST请求且有数据,设置适当的头部
if (method === 'POST' && data) {
request. setRequestHeader ( 'Content-Type' , 'application/json' );
}
request. onreadystatechange = function () {
if (request.readyState === 4 ) {
if (request.status >= 200 && request.status < 300 ) {
try {
const response = JSON . parse (request.responseText);
resolve (response);
} catch (error) {
reject ( new Error ( '响应数据格式错误' ));
}
} else {
reject ( new Error ( `请求失败: ${ request . status } ${ request . statusText }` ));
}
}
};
request. ontimeout = function () {
reject ( new Error ( '请求超时' ));
};
request. onerror = function () {
reject ( new Error ( '网络错误' ));
};
request. send (data ? JSON . stringify (data) : null );
});
}
// 使用示例
makeRequest ( 'GET' , '/api/products' )
. then ( products => {
console. log ( '产品列表:' , products);
})
. catch ( error => {
console. error ( '获取产品列表失败:' , error.message);
});
(request.responseText);
console. log ( '外部数据:' , data);
} else {
console. error ( '跨域请求失败:' , request.statusText);
}
}
};
request. send ();
}
window[callbackName];
document.head. removeChild (script);
};
// 创建script元素
const script = document. createElement ( 'script' );
// 构建请求URL,添加回调参数
const separator = url. includes ( '?' ) ? '&' : '?' ;
script.src = `${ url }${ separator }callback=${ callbackName }` ;
// 添加script元素到文档中,开始加载
document.head. appendChild (script);
}
// 使用示例
jsonpRequest ( 'https://api.example.com/weather?city=beijing' , function ( data ) {
console. log ( '天气数据:' , data);
});
await
response.
json
();
console. log ( '用户数据:' , userData);
return userData;
} catch (error) {
console. error ( '获取用户数据失败:' , error.message);
throw error;
}
}
// 使用Fetch API进行POST请求
async function createUser ( userData ) {
try {
const response = await fetch ( '/api/users' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify (userData)
});
if ( ! response.ok) {
throw new Error ( `创建用户失败: ${ response . status }` );
}
const newUser = await response. json ();
console. log ( '用户创建成功:' , newUser);
return newUser;
} catch (error) {
console. error ( '创建用户失败:' , error.message);
throw error;
}
}
() {
console. log ( 'SSE连接已建立' );
};
// 监听错误事件
eventSource. onerror = function ( error ) {
console. error ( 'SSE连接错误:' , error);
};
// 监听自定义事件类型
eventSource. addEventListener ( 'urgent' , function ( event ) {
const urgentMessage = JSON . parse (event.data);
console. log ( '紧急消息:' , urgentMessage);
showUrgentAlert (urgentMessage);
});
function displayNotification ( notification ) {
const notificationDiv = document. createElement ( 'div' );
notificationDiv.className = 'notification' ;
notificationDiv.textContent = notification.message;
document.body. appendChild (notificationDiv);
}
function showUrgentAlert ( message ) {
alert ( `紧急通知: ${ message . content }` );
}
onmessage
=
function
(
event
) {
const message = JSON . parse (event.data);
console. log ( '收到消息:' , message);
switch (message.type) {
case 'chat' :
displayChatMessage (message);
break ;
case 'user_joined' :
displaySystemMessage ( `${ message . username } 加入了聊天室` );
break ;
case 'user_left' :
displaySystemMessage ( `${ message . username } 离开了聊天室` );
break ;
}
};
// 连接关闭时的处理
socket. onclose = function ( event ) {
console. log ( 'WebSocket连接已关闭:' , event.code, event.reason);
};
// 错误处理
socket. onerror = function ( error ) {
console. error ( 'WebSocket错误:' , error);
};
// 发送聊天消息
function sendChatMessage ( text ) {
if (socket.readyState === WebSocket. OPEN ) {
socket. send ( JSON . stringify ({
type: 'chat' ,
message: text,
timestamp: new Date (). toISOString ()
}));
}
}
function displayChatMessage ( message ) {
const messageDiv = document. createElement ( 'div' );
messageDiv.innerHTML = `<strong>${ message . username }:</strong> ${ message . text }` ;
document. getElementById ( 'chatMessages' ). appendChild (messageDiv);
}
function displaySystemMessage ( text ) {
const messageDiv = document. createElement ( 'div' );
messageDiv.className = 'system-message' ;
messageDiv.textContent = text;
document. getElementById ( 'chatMessages' ). appendChild (messageDiv);
}
Promise
((
resolve
,
reject
)
=>
{
this .pendingRequests. push ({ data, resolve, reject });
// 清除之前的定时器
if ( this .timeoutId) {
clearTimeout ( this .timeoutId);
}
// 设置新的定时器,延迟执行批处理
this .timeoutId = setTimeout (() => {
this . executeBatch ();
}, this .delay);
});
}
// 执行批处理请求
async executeBatch () {
if ( this .pendingRequests. length === 0 ) return ;
const requests = this .pendingRequests. splice ( 0 );
const batchData = requests. map ( req => req.data);
try {
const response = await fetch ( this .endpoint, {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ batch: batchData })
});
const results = await response. json ();
// 将结果分发给对应的Promise
requests. forEach (( req , index ) => {
req. resolve (results[index]);
});
} catch (error) {
// 所有请求都失败
requests. forEach ( req => {
req. reject (error);
});
}
}
}
// 使用示例
const batchManager = new BatchRequestManager ( '/api/batch' );
// 多个组件可以同时添加请求,它们会被自动合并
Promise . all ([
batchManager. addRequest ({ type: 'user' , id: 1 }),
batchManager. addRequest ({ type: 'profile' , id: 1 }),
batchManager. addRequest ({ type: 'settings' , id: 1 })
]). then ( results => {
console. log ( '批处理结果:' , results);
});
const method = options.method || 'GET' ;
const body = options.body || '' ;
return `${ method }:${ url }:${ body }` ;
}
// 获取缓存数据
get ( key ) {
const cached = this .cache. get (key);
if ( ! cached) return null ;
// 检查是否过期
if (Date. now () > cached.expiry) {
this .cache. delete (key);
return null ;
}
return cached.data;
}
// 设置缓存数据
set ( key , data , ttl = this .defaultTTL) {
// 如果缓存已满,删除最老的条目
if ( this .cache.size >= this .maxSize) {
const firstKey = this .cache. keys (). next ().value;
this .cache. delete (firstKey);
}
this .cache. set (key, {
data,
expiry: Date. now () + ttl
});
}
// 带缓存的请求方法
async fetch ( url , options = {}, ttl ) {
const key = this . generateKey (url, options);
// 尝试从缓存获取
const cached = this . get (key);
if (cached) {
console. log ( '从缓存返回数据:' , url);
return cached;
}
// 发送实际请求
console. log ( '发送网络请求:' , url);
const response = await fetch (url, options);
const data = await response. json ();
// 存入缓存
this . set (key, data, ttl);
return data;
}
}
// 使用示例
const cache = new RequestCache ();
// 第一次请求会发送网络请求
cache. fetch ( '/api/products' ). then ( data => {
console. log ( '产品数据:' , data);
});
// 短时间内的相同请求会从缓存返回
setTimeout (() => {
cache. fetch ( '/api/products' ). then ( data => {
console. log ( '缓存数据:' , data);
});
}, 1000 );
const
data
=
JSON
.
parse
(request.responseText);
console. log ( '获取到的数据:' , data);
} catch (error) {
console. error ( '解析JSON失败:' , error);
}
} else {
// 请求失败
console. error ( '请求失败,状态码:' , request.status);
}
}
};
// 发送请求
request. send ();
();
console. log ( '获取到的数据:' , data);
return data;
} catch (error) {
console. error ( '请求错误:' , error);
}
}
// 调用函数
// fetchData();
// 使用Fetch API发送POST请求
async function postData ( url , data ) {
try {
const response = await fetch (url, {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json'
},
body: JSON . stringify (data)
});
if ( ! response.ok) {
throw new Error ( '请求失败' );
}
const result = await response. json ();
return result;
} catch (error) {
console. error ( 'POST请求错误:' , error);
}
} 'POST'
&&
data) {
request. setRequestHeader ( 'Content-Type' , 'application/json' );
}
// 设置响应处理函数
request. onreadystatechange = function () {
if (request.readyState === 4 ) {
if (request.status >= 200 && request.status < 300 ) {
// 请求成功
try {
const response = JSON . parse (request.responseText);
resolve (response);
} catch (error) {
resolve (request.responseText);
}
} else {
// 请求失败
reject ( new Error ( '请求失败,状态码: ' + request.status));
}
}
};
// 处理网络错误
request. onerror = function () {
reject ( new Error ( '网络错误' ));
};
// 发送请求
if (data && method === 'POST' ) {
request. send ( JSON . stringify (data));
} else {
request. send ();
}
});
}
// 使用示例
// httpRequest('GET', '/api/users')
// .then(data => console.log('数据:', data))
// .catch(error => console.error('错误:', error));
// httpRequest('POST', '/api/users', {name: '张三', age: 20})
// .then(data => console.log('创建成功:', data))
// .catch(error => console.error('错误:', error));