云计算百科
云计算领域专业知识百科平台

【Laya】HttpRequest 网络请求

Laya.HttpRequest 网络请求使用指南

简介

Laya.HttpRequest 是 LayaAir 引擎提供的 HTTP 网络请求类,封装了原生 XMLHttpRequest 对象,支持 GET、POST、HEAD 等多种 HTTP 方法,可实现与后端服务器的数据交互。

适用场景:

  • 向服务器请求 JSON、文本、二进制数据
  • 表单提交和文件上传
  • RESTful API 调用
  • 游戏数据同步、排行榜、用户登录等

工作原理:

创建请求 → 设置事件监听 → 发送请求 → 接收响应 → 处理数据

核心优势:

优势说明
异步请求 不阻塞主线程,保证游戏流畅运行
多种格式 支持 text、json、xml、arraybuffer 等响应类型
进度监控 支持下载进度监听
事件驱动 基于 EventDispatcher,事件处理灵活

目录

  • API 参考
  • 基础用法
  • 实用示例
  • 高级技巧
  • 最佳实践

API 参考

构造函数

方法说明
new Laya.HttpRequest() 创建一个新的 HttpRequest 对象

发送请求

方法参数返回值说明
send(url, data?, method?, responseType?, headers?) url: 地址data: 发送数据method: 请求方法responseType: 响应类型headers: 请求头 void 发送 HTTP 请求

参数详情:

参数类型默认值说明
url string 请求地址(需遵守同源策略)
data any null 发送的数据
method "get" | "post" | "head" "get" HTTP 请求方法
responseType string "text" 响应类型:"text" / "json" / "xml" / "arraybuffer"
headers string[] null HTTP 请求头,格式:["key", "value"]

属性

属性类型只读说明
url string 请求的地址
data any 返回的数据
http any 原生 XMLHttpRequest 对象引用

方法

方法返回值说明
reset() void 重置对象,清除所有事件监听器和数据

事件

事件说明
Laya.Event.PROGRESS 请求进度变化时触发
Laya.Event.COMPLETE 请求完成时触发
Laya.Event.ERROR 请求失败时触发

基础用法

1. GET 请求(最常用)

// 创建请求对象
let http = new Laya.HttpRequest();

// 监听事件
http.once(Laya.Event.PROGRESS, this, this.onProgress);
http.once(Laya.Event.COMPLETE, this, this.onComplete);
http.once(Laya.Event.ERROR, this, this.onError);

// 发送 GET 请求
http.send("https://api.example.com/user/info?id=123");

// 进度回调
private onProgress(e: any): void {
console.log("加载进度:", e);
}

// 成功回调
private onComplete(e: any): void {
console.log("响应数据:", http.data);
}

// 失败回调
private onError(e: any): void {
console.log("请求失败:", e);
}

2. POST 请求(发送数据)

let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, this.onComplete);
http.once(Laya.Event.ERROR, this, this.onError);

// 发送 POST 请求,数据为键值对格式
let postData = "name=player1&score=100&level=5";
http.send("https://api.example.com/score/submit", postData, "post");

private onComplete(e: any): void {
let response = JSON.parse(http.data);
console.log("提交成功:", response);
}

3. 请求 JSON 数据

let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, (e: any) => {
// 直接使用 JSON.parse 解析
let data = JSON.parse(http.data);
console.log("用户名:", data.name);
console.log("等级:", data.level);
});

http.send("https://api.example.com/config", null, "get", "text");

4. 设置请求头

let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, this.onComplete);

// 设置自定义请求头
let headers = [
"Content-Type", "application/json",
"Authorization", "Bearer token123",
"X-Custom-Header", "custom-value"
];

http.send("https://api.example.com/data", null, "get", "text", headers);


实用示例

示例1: 用户登录验证

@regClass()
export class LoginManager extends Laya.Script {
private static readonly LOGIN_URL = "https://api.example.com/auth/login";

/**
* 发起登录请求
*/

public login(username: string, password: string): Promise<void> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
let response = JSON.parse(http.data);

if (response.code === 200) {
// 登录成功,保存 token
Laya.LocalStorage.setItem("token", response.data.token);
Laya.LocalStorage.setItem("userId", response.data.userId);
resolve();
} else {
reject(new Error(response.message || "登录失败"));
}
} catch (e) {
reject(new Error("数据解析失败"));
}
});

http.once(Laya.Event.ERROR, this, (e: any) => {
reject(new Error("网络请求失败"));
});

// 构建请求数据
let postData = `username=${username}&password=${password}`;
http.send(LoginManager.LOGIN_URL, postData, "post");
});
}

/**
* 获取保存的 token
*/

public getToken(): string | null {
return Laya.LocalStorage.getItem("token");
}
}

示例2: 排行榜数据加载

@regClass()
export class RankManager extends Laya.Script {
private static readonly RANK_URL = "https://api.example.com/rank/list";
private isLoading: boolean = false;

/**
* 加载排行榜数据
*/

public loadRankList(type: number = 1): Promise<any[]> {
return new Promise((resolve, reject) => {
if (this.isLoading) {
reject(new Error("正在加载中…"));
return;
}

this.isLoading = true;
let http = new Laya.HttpRequest();

// 显示加载进度
http.on(Laya.Event.PROGRESS, this, (e: any) => {
console.log("排行榜加载进度:", e);
});

http.once(Laya.Event.COMPLETE, this, () => {
this.isLoading = false;
try {
let response = JSON.parse(http.data);

if (response.code === 200) {
resolve(response.data.list);
} else {
reject(new Error(response.message));
}
} catch (e) {
reject(new Error("数据解析失败"));
}
});

http.once(Laya.Event.ERROR, this, () => {
this.isLoading = false;
reject(new Error("网络错误"));
});

// 请求排行榜数据
let url = `${RankManager.RANK_URL}?type=${type}&limit=100`;
http.send(url, null, "get", "text");
});
}
}

示例3: 游戏配置预加载

@regClass()
export class ConfigManager extends Laya.Script {
private static config: any = null;

/**
* 加载游戏配置
*/

public static loadConfig(): Promise<void> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
ConfigManager.config = JSON.parse(http.data);
console.log("配置加载成功:", ConfigManager.config);
resolve();
} catch (e) {
reject(new Error("配置解析失败"));
}
});

http.once(Laya.Event.ERROR, this, () => {
reject(new Error("配置加载失败"));
});

http.send("https://cdn.example.com/config/game_config.json", null, "get", "text");
});
}

/**
* 获取配置项
*/

public static get(key: string): any {
return ConfigManager.config?.[key];
}

/**
* 游戏启动时加载配置
*/

public static async init(): Promise<void> {
await ConfigManager.loadConfig();
console.log("服务器地址:", ConfigManager.get("serverUrl"));
console.log("游戏版本:", ConfigManager.get("version"));
}
}

示例4: 文件上传(multipart/form-data)

@regClass()
export class UploadManager extends Laya.Script {
/**
* 上传玩家头像
*/

public uploadAvatar(imageData: ArrayBuffer): Promise<string> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
let response = JSON.parse(http.data);

if (response.code === 200) {
resolve(response.data.url);
} else {
reject(new Error(response.message));
}
} catch (e) {
reject(new Error("上传失败"));
}
});

http.once(Laya.Event.ERROR, this, () => {
reject(new Error("网络错误"));
});

// 设置上传请求头
let token = Laya.LocalStorage.getItem("token");
let headers = [
"Authorization", `Bearer ${token}`
];

// 发送上传请求(需要后端支持)
http.send("https://api.example.com/user/avatar", imageData, "post", "arraybuffer", headers);
});
}
}

示例5: 带重试机制的请求

@regClass()
export class RetryHttpClient extends Laya.Script {
private static readonly MAX_RETRY = 3;
private static readonly RETRY_DELAY = 1000;

/**
* 带重试的 HTTP 请求
*/

public static request(url: string, data: any = null, method: string = "get", retryCount: number = 0): Promise<any> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
let response = JSON.parse(http.data);

if (response.code === 200) {
resolve(response.data);
} else {
// 业务错误,不重试
reject(new Error(response.message));
}
} catch (e) {
// JSON 解析失败,可能是其他格式
resolve(http.data);
}
});

http.once(Laya.Event.ERROR, this, () => {
if (retryCount < this.MAX_RETRY) {
console.log(`请求失败,${this.RETRY_DELAY}ms 后进行第 ${retryCount + 1} 次重试…`);

// 延迟重试
Laya.timer.once(this.RETRY_DELAY, this, () => {
this.request(url, data, method, retryCount + 1)
.then(resolve)
.catch(reject);
});
} else {
reject(new Error("请求失败,已达最大重试次数"));
}
});

http.send(url, data, method, "text");
});
}

/**
* 使用示例
*/

public static fetchData(): void {
this.request("https://api.example.com/data")
.then(data => {
console.log("请求成功:", data);
})
.catch(err => {
console.error("请求失败:", err.message);
});
}
}

示例6: 请求队列管理

@regClass()
export class RequestQueue extends Laya.Script {
private static queue: Array<() => Promise<any>> = [];
private static isProcessing: boolean = false;
private static readonly MAX_CONCURRENT = 3;
private static currentCount: number = 0;

/**
* 添加请求到队列
*/

public static add(requestFn: () => Promise<any>): Promise<any> {
return new Promise((resolve, reject) => {
this.queue.push(async () => {
try {
let result = await requestFn();
resolve(result);
} catch (e) {
reject(e);
}
});
this.processQueue();
});
}

/**
* 处理队列
*/

private static processQueue(): void {
if (this.isProcessing || this.queue.length === 0 || this.currentCount >= this.MAX_CONCURRENT) {
return;
}

this.isProcessing = true;

while (this.queue.length > 0 && this.currentCount < this.MAX_CONCURRENT) {
this.currentCount++;
let requestFn = this.queue.shift()();

requestFn().finally(() => {
this.currentCount;
this.processQueue();
});
}

this.isProcessing = false;
}

/**
* 使用示例:批量加载资源
*/

public static loadBatchResources(urls: string[]): Promise<any[]> {
let promises = urls.map(url => {
return this.add(() => {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();
http.once(Laya.Event.COMPLETE, this, () => resolve(http.data));
http.once(Laya.Event.ERROR, this, () => reject(new Error(`加载失败: ${url}`)));
http.send(url);
});
});
});

return Promise.all(promises);
}
}


高级技巧

1. 使用 Promise 封装

class HttpClient {
/**
* GET 请求
*/

public static get(url: string, headers?: string[]): Promise<any> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
resolve(JSON.parse(http.data));
} catch (e) {
resolve(http.data);
}
});

http.once(Laya.Event.ERROR, this, (e: any) => {
reject(e);
});

http.send(url, null, "get", "text", headers);
});
}

/**
* POST 请求
*/

public static post(url: string, data: any, headers?: string[]): Promise<any> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
resolve(JSON.parse(http.data));
} catch (e) {
resolve(http.data);
}
});

http.once(Laya.Event.ERROR, this, (e: any) => {
reject(e);
});

http.send(url, data, "post", "text", headers);
});
}
}

// 使用示例
HttpClient.get("https://api.example.com/data")
.then(data => console.log(data))
.catch(err => console.error(err));

2. 请求超时处理

class TimeoutHttpClient {
private static readonly TIMEOUT = 10000; // 10秒超时

public static requestWithTimeout(url: string, timeout: number = this.TIMEOUT): Promise<any> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();
let isComplete = false;
let timer: any;

// 超时计时器
timer = Laya.timer.once(timeout, this, () => {
if (!isComplete) {
isComplete = true;
http.reset(); // 中断请求
reject(new Error("请求超时"));
}
});

http.once(Laya.Event.COMPLETE, this, () => {
Laya.timer.clear(timer);
if (!isComplete) {
isComplete = true;
try {
resolve(JSON.parse(http.data));
} catch (e) {
resolve(http.data);
}
}
});

http.once(Laya.Event.ERROR, this, (e: any) => {
Laya.timer.clear(timer);
if (!isComplete) {
isComplete = true;
reject(e);
}
});

http.send(url);
});
}
}

3. 请求缓存

class CachedHttpClient {
private static cache: Map<string, { data: any; timestamp: number }> = new Map();
private static readonly CACHE_DURATION = 60000; // 缓存1分钟

/**
* 带缓存的 GET 请求
*/

public static getCached(url: string): Promise<any> {
let now = Date.now();
let cached = this.cache.get(url);

if (cached && (now cached.timestamp) < this.CACHE_DURATION) {
console.log("使用缓存数据:", url);
return Promise.resolve(cached.data);
}

return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
let data = JSON.parse(http.data);
// 保存到缓存
this.cache.set(url, { data, timestamp: now });
resolve(data);
} catch (e) {
resolve(http.data);
}
});

http.once(Laya.Event.ERROR, this, (e: any) => {
reject(e);
});

http.send(url);
});
}

/**
* 清除缓存
*/

public static clearCache(url?: string): void {
if (url) {
this.cache.delete(url);
} else {
this.cache.clear();
}
}
}

4. 复用 HttpRequest 对象

@regClass()
export class ReusableHttpClient extends Laya.Script {
private http: Laya.HttpRequest;
private onCompleteHandlers: Array<(data: any) => void> = [];
private onErrorHandlers: Array<(error: any) => void> = [];

constructor() {
super();
this.http = new Laya.HttpRequest();
this.http.on(Laya.Event.COMPLETE, this, this.onComplete);
this.http.on(Laya.Event.ERROR, this, this.onError);
}

/**
* 发送请求
*/

public send(url: string, data?: any, method?: string): Promise<any> {
return new Promise((resolve, reject) => {
this.onCompleteHandlers.push(resolve);
this.onErrorHandlers.push(reject);
this.http.send(url, data, method);
});
}

private onComplete(): void {
let handlers = this.onCompleteHandlers;
this.onCompleteHandlers = [];
handlers.forEach(fn => fn(this.http.data));
}

private onError(e: any): void {
let handlers = this.onErrorHandlers;
this.onErrorHandlers = [];
handlers.forEach(fn => fn(e));
}

onDestroy(): void {
this.http.reset();
this.http.offAll();
}
}


最佳实践

1. 每次请求创建新对象

// ✅ 推荐:每次请求创建新对象
let http1 = new Laya.HttpRequest();
http1.send(url1);

let http2 = new Laya.HttpRequest();
http2.send(url2);

// ❌ 不推荐:复用同一对象可能导致数据混乱
let http = new Laya.HttpRequest();
http.send(url1);
http.send(url2); // 可能会清除第一个请求的数据

2. 使用 once 而非 on 监听事件

// ✅ 推荐:使用 once,自动移除监听
http.once(Laya.Event.COMPLETE, this, this.onComplete);

// ❌ 不推荐:使用 on,需要手动移除
http.on(Laya.Event.COMPLETE, this, this.onComplete);
// 之后需要手动 off 移除监听

3. 统一的错误处理

class ApiClient {
private static readonly BASE_URL = "https://api.example.com";

/**
* 统一请求方法
*/

private static request(endpoint: string, data?: any, method?: string, headers?: string[]): Promise<any> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();

http.once(Laya.Event.COMPLETE, this, () => {
try {
let response = JSON.parse(http.data);

// 统一处理业务状态码
switch (response.code) {
case 200:
resolve(response.data);
break;
case 401:
// token 过期,重新登录
this.handleTokenExpired();
reject(new Error("登录已过期"));
break;
case 403:
reject(new Error("无权限访问"));
break;
default:
reject(new Error(response.message || "请求失败"));
}
} catch (e) {
reject(new Error("数据解析失败"));
}
});

http.once(Laya.Event.ERROR, this, (e: any) => {
reject(new Error("网络连接失败"));
});

let url = `${this.BASE_URL}${endpoint}`;
http.send(url, data, method, "text", headers);
});
}

private static handleTokenExpired(): void {
// 清除登录状态
Laya.LocalStorage.setItem("token", "");
// 跳转到登录页
Laya.Scene.open("scenes/LoginScene.scene");
}
}

4. 添加请求签名(安全)

class SecureApiClient {
private static readonly APP_KEY = "your_app_key";
private static readonly APP_SECRET = "your_app_secret";

/**
* 生成签名
*/

private static sign(params: Record<string, any>): string {
// 按字母顺序排序
let sortedKeys = Object.keys(params).sort();
let signStr = sortedKeys.map(key => `${key}=${params[key]}`).join("&");
signStr += `&app_secret=${this.APP_SECRET}`;
return Laya.Utils.toMD5(signStr);
}

/**
* 发起带签名的请求
*/

public static signedRequest(endpoint: string, params: Record<string, any>): Promise<any> {
// 添加公共参数
params.app_key = this.APP_KEY;
params.timestamp = Date.now();
params.nonce = Math.random().toString(36).substring(2);

// 生成签名
params.sign = this.sign(params);

// 构建查询字符串
let queryString = Object.keys(params)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
.join("&");

let http = new Laya.HttpRequest();
return new Promise((resolve, reject) => {
http.once(Laya.Event.COMPLETE, this, () => {
try {
let response = JSON.parse(http.data);
resolve(response.data);
} catch (e) {
reject(new Error("数据解析失败"));
}
});

http.once(Laya.Event.ERROR, this, () => {
reject(new Error("请求失败"));
});

http.send(`${endpoint}?${queryString}`);
});
}
}

5. 场景切换时取消请求

@regClass()
export class GameScene extends Laya.Scene {
private activeRequests: Laya.HttpRequest[] = [];

/**
* 发送可追踪的请求
*/

public trackedRequest(url: string): Promise<any> {
return new Promise((resolve, reject) => {
let http = new Laya.HttpRequest();
this.activeRequests.push(http);

http.once(Laya.Event.COMPLETE, this, () => {
// 从列表中移除
let index = this.activeRequests.indexOf(http);
if (index > 1) this.activeRequests.splice(index, 1);

try {
resolve(JSON.parse(http.data));
} catch (e) {
resolve(http.data);
}
});

http.once(Laya.Event.ERROR, this, () => {
let index = this.activeRequests.indexOf(http);
if (index > 1) this.activeRequests.splice(index, 1);
reject(new Error("请求失败"));
});

http.send(url);
});
}

/**
* 场景销毁时取消所有请求
*/

onDestroy(): void {
// 取消所有活跃的请求
this.activeRequests.forEach(http => {
http.reset();
});
this.activeRequests = [];
}
}


注意事项

  • 同源策略:浏览器的同源安全策略要求请求 URL 与脚本具有相同的主机名和端口
  • 每次新建对象:建议每次请求使用新的 HttpRequest 对象,避免数据混乱
  • 使用 once 监听:推荐使用 once() 而非 on() 监听事件,自动移除避免内存泄漏
  • 错误处理:始终监听 Event.ERROR 事件处理请求失败情况
  • HTTPS 通信:生产环境建议使用 HTTPS 确保数据传输安全
  • 数据验证:接收数据后验证格式和内容,避免恶意数据导致游戏异常

  • 相关文档

    • Laya.Event 使用说明
    • Laya.LocalStorage 使用说明
    • Laya.Socket WebSocket使用说明
    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【Laya】HttpRequest 网络请求
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!