| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- import { _decorator, Component, Enum, EventHandler } from 'cc';
- import { Log } from '../utils/Log';
- import { RC4 } from '../utils/RC4';
- import { HttpSystem, HostData, ErrorDataType } from './HttpSystem';
- import { HttpRequest } from './HttpRequest';
- const { ccclass, property, executionOrder } = _decorator;
- /**
- * Http请求方法
- */
- export enum HttpMethod {
- GET = "get",
- POST = "post"
- }
- /**
- * Http请求的数据类型
- */
- export enum ResponseType {
- Arraybuffer,
- Blob,
- Document,
- Json,
- Text
- }
- export enum HttpResponseCode {
- /**
- * 成功
- */
- Success,
- /**
- * 没有登录
- */
- NoLogin,
- /**
- * 未知错误
- */
- UnKnowError,
- /**
- * 密钥错误
- */
- KeyError
- }
- /**
- * Http组件
- * @description 建议使用@requireComponent(Http)、this.getComponent(Http)来配合使用Http组件
- * @description post模式暂时还不支持消息加密
- * @author 袁浩
- */
- @ccclass('Http')
- @executionOrder(-1)
- export class Http extends Component {
- @property({ tooltip: "HttpConfig中配置的服务端别名,不填则取HttpConfig中的默认值" })
- public hostAlias: string = "";
- @property({ tooltip: "请求是否应当带有授权信息,如cookie或授权header头" })
- public withCredentials: boolean = false;
- @property({ tooltip: "该请求的超时时间(毫秒),0为20秒", step: 1, min: 0 })
- public timeout: number = 0;
- @property({ type: Enum(ResponseType), tooltip: "返回的数据格式" })
- public responseType: ResponseType = ResponseType.Json;
- @property({ type: EventHandler, tooltip: "加载的进度回调函数" })
- public onProgress: EventHandler;
- @property({ tooltip: "消息加密" })
- public useEncrypt: boolean = true;
- @property({ tooltip: "是否打印消息" })
- public useLog: boolean = true;
- /**
- * 收到数据后的公共回调,返回值为是否执行后续调用
- */
- public static onData: (data: any) => boolean = () => { return true; }
- /**
- * 密钥错误
- */
- public static onKeyError: () => void = () => { }
- private get config(): HostData {
- return HttpSystem.getConfig(this.hostAlias);
- }
- public getRootURL(): string {
- var port = `:${this.config.port}`;
- if (this.config.SSL && this.config.port == 443 || !this.config.SSL && this.config.port == 80) {
- port = '';
- }
- return `${this.config.SSL ? "https://" : "http://"}${this.config.host}${port}`;
- }
- private headerObj: any;
- /**
- * 给指定的HTTP请求头赋值.在这之前,您必须确认已经调用 open() 方法打开了一个url.
- * @param header 将要被赋值的请求头名称.
- * @param value 给指定的请求头赋的值.
- */
- public setRequestHeader(header: string, value: string): void {
- if (!this.headerObj) {
- this.headerObj = {};
- }
- this.headerObj[header] = value;
- }
- /**
- * 所有的请求数据
- */
- protected requestMap: any = {};
- /**
- * 发送请求
- * @param path 路径
- * @param data 数据
- * @param method 方法
- * @returns
- */
- public async send(path: string, data: any = {}, method: HttpMethod = HttpMethod.GET, useEncrypt?: boolean, useTail = true) {
- let result = await this._send(path, data, method, useEncrypt, useTail);
- if (result && result.code == HttpResponseCode.KeyError) {
- HttpSystem.resetPublicKey();
- result = await this._send(path, data, method, useEncrypt, useTail);
- if (result && result.code == HttpResponseCode.KeyError) {//续签密钥失败
- Http.onKeyError();
- return { code: HttpResponseCode.KeyError, data: HttpSystem.getErrorDataType() != ErrorDataType.Null ? {} : null };
- }
- }
- return result;
- }
- private _send(path: string, data: any = {}, method: HttpMethod = HttpMethod.GET, useEncrypt?: boolean, useTail = true) {
- return new Promise<any>((resolve: (data: any) => void, reject) => {
- if (useEncrypt === undefined) {
- useEncrypt = this.useEncrypt;
- }
- var self = this;
- var request = new HttpRequest((url: string) => {
- if (!this.isValid) {
- return;
- }
- console.error(`http请求[${url}]失败`);
- delete self.requestMap[url];
- var errorDataType = HttpSystem.getErrorDataType();
- if (errorDataType == ErrorDataType.Throw) {
- reject();
- }
- else {
- resolve(errorDataType == ErrorDataType.Null ? null : {});
- }
- }, (httpRequest: HttpRequest) => {
- if (!this.isValid) {
- return;
- }
- var errorDataType = HttpSystem.getErrorDataType();
- var response = httpRequest.response;
- if (!response && errorDataType == ErrorDataType.Object) {
- response = {};
- }
- if (useEncrypt) {
- response = HttpSystem.decrypt(response);
- self.responseType == ResponseType.Json && (response = JSON.parse(response));
- }
- let url = httpRequest.url.substring(0, httpRequest.url.indexOf('?'));
- this.useLog && HttpSystem.useDebugLog && Log.info(`http请求[${url}]成功,数据为${self.responseType == ResponseType.Json ? JSON.stringify(response) : response}`);
- Http.onData(response) && resolve(response);
- delete self.requestMap[httpRequest.url];
- }, (loaded: number, total: number): void => {
- self.onProgress.emit([loaded, total]);
- });
- request.withCredentials = this.withCredentials;
- request.timeout = this.timeout || 20000;
- switch (this.responseType) {
- case ResponseType.Json:
- request.responseType = "json";
- break;
- case ResponseType.Arraybuffer:
- request.responseType = "arraybuffer";
- break;
- case ResponseType.Blob:
- request.responseType = "blob";
- break;
- case ResponseType.Document:
- request.responseType = "document";
- break;
- case ResponseType.Text:
- request.responseType = "text";
- break;
- default:
- request.responseType = "";
- break;
- }
- if (useEncrypt) {//如果消息加密
- data = data || {};
- data.timestamp = HttpSystem.serverTime;
- }
- let getData: string = typeof data == 'object' ? HttpSystem.dataToString(data) : data;
- let postData = method == HttpMethod.GET ? null : (typeof data == 'object' ? JSON.stringify(data) : data);
- let url: string = this.getRootURL() + (method == HttpMethod.GET ? path + "?" + getData : path);
- this.useLog && HttpSystem.useDebugLog && Log.info(`http请求[${url}]发送`);
- if (useEncrypt) {//如果消息加密
- if (method == HttpMethod.GET) {
- getData = HttpSystem.encrypt(getData, method);
- }
- else {
- postData = HttpSystem.encrypt(postData, method);
- }
- }
- useTail && (getData += HttpSystem.tailString);
- url = this.getRootURL() + (method == HttpMethod.GET ? path + "?" + getData : path);
- if (this.headerObj) {
- for (let key in this.headerObj) {
- request.setRequestHeader(key, this.headerObj[key]);
- }
- }
- self.requestMap[url] = request;
- request.open(url, method);
- request.send(postData);
- });
- }
- /**
- * 撤销http请求
- * 在onDestroy中记得调用,防止页面关闭了,请求还在执行导致产生一系列错误和内存泄漏(需要详细测试,可能并不需要如此)
- * @param path {string} http请求的地址
- * @param data {any} 请求所携带的数据
- */
- public cancel(path: string): void {
- for (var key in this.requestMap) {
- if (key.indexOf(this.getRootURL() + path) == 0) {
- var request: XMLHttpRequest = this.requestMap[key];
- request.abort();
- delete this.requestMap[key];
- }
- }
- }
- /**
- * 撤销所有http请求
- */
- public cancelAll(): void {
- for (var key in this.requestMap) {
- var request: XMLHttpRequest = this.requestMap[key];
- request.abort();
- }
- this.requestMap = {};
- }
- public onDestroy() {
- this.cancelAll();
- }
- }
|