Fetch API 请求封装的最初实现
标签:DX, TypeScript
分类:摘抄本
11分钟阅读
最前
正文
src\Util\Rest.ts
import moment from "moment";
import { RestException } from "./Exceptions";
import { CollectionUtil, StringUtil } from "./Helper";
enum Method {
GET = "GET",
POST = "POST",
PUT = "PUT",
DELETE = "DELETE"
}
interface ServerError {
content: string;
code: string;
level: string;
}
export const RestDateTimeFormat = "YYYY-MM-DD HH:mm:ss";
class RestUtil {
private readonly baseUrl = "/api";
private readonly headers = new Headers([
["response-format", "json"],
["Accept", "*/*"],
["Accept-Encoding", "gzip, deflate"],
["Content-Type", "application/json;charset=utf-8"]
]);
private reLoginHandler: () => void;
private CreateRequestInit = (method: Method): RequestInit => {
return {
method: method,
headers: new Headers(this.headers),
credentials: "include",
mode: "same-origin"
};
}
public Get = (url: string) => {
return new RestRequestWrapper(url, this, this.CreateRequestInit(Method.GET));
}
public Post = (url: string) => {
return new RestRequestWrapper(url, this, this.CreateRequestInit(Method.POST));
}
public Put = (url: string) => {
return new RestRequestWrapper(url, this, this.CreateRequestInit(Method.PUT));
}
public Delete = (url: string) => {
return new RestRequestWrapper(url, this, this.CreateRequestInit(Method.DELETE));
}
private GetResponseInternal = async (url: string, requestInt: RequestInit) => {
const response = await fetch(this.baseUrl + url, requestInt);
switch (response.status) {
case 200: //200 客户端请求已成功
case 204: //204 服务器没有返回内容
break;
case 400: // 400 客户端提交的数据在服务器端校验不通过时会收到该代码
case 500:
{
const text = await response.text();
let error: ServerError;
try {
error = JSON.parse(text) as ServerError;
}
catch (exception) {
console.log(exception);
console.log(text);
}
if (error != null) {
throw new RestException(response.url, response.status, error.content, error.code, error.level);
}
else {
if (response.status === 400) {
throw new RestException(response.url, response.status, "无效的请求");
}
else {
throw new RestException(response.url, response.status, "服务器异常", null, null, text);
}
}
}
case 401: //401 未授权的用户。用户未登录或者Session过期后去访问服务器的资源会收到该值
if (this.reLoginHandler != null)
this.reLoginHandler();
throw new RestException(response.url, response.status, "登录超时或用户未授权,请重新登录");
case 404: //404 资源不存在
throw new RestException(response.url, response.status, "无法连接服务器");
default:
throw new RestException(response.url, response.status, "未知错误");
}
return response;
}
public GetResponse = (url: string, requestInit: RequestInit) => this.GetResponseInternal(url, requestInit);
public GetTResponse = async <T>(url: string, requestInit: RequestInit) => {
const response = await this.GetResponse(url, requestInit);
const text = await response.text();
if (!StringUtil.IsNullOrEmpty(text)) {
return JSON.parse(text) as T;
} else {
return null;
}
}
public SetReLoginHandler = (handler: () => void) => {
this.reLoginHandler = handler;
}
}
export const Rest = new RestUtil();
其中,RestRequestWrapper 定义如下:
src\Util\Rest.ts
class RestRequestWrapper {
private url: string;
private rest: RestUtil;
private requestInit: RequestInit;
private parameters = "";
constructor(url: string, rest: RestUtil, request: RequestInit) {
this.url = url;
this.rest = rest;
this.requestInit = request;
}
public AddParameter = (
key: string,
value: string | number | moment.Moment,
) => {
if (moment.isMoment(value)) {
value = value.format(RestDateTimeFormat);
}
if (this.parameters.length === 0) {
this.parameters += `?`;
} else {
this.parameters += `&`;
}
this.parameters += `${key}=${value}`;
return this;
};
public AddParameterArray = (
key: string,
values: Array<string | number | moment.Moment>,
) => {
if (!CollectionUtil.IsNullOrEmpty(values))
for (const value of values) {
this.AddParameter(key, value);
}
return this;
};
public AddBody = (body: Object) => {
this.requestInit.body = JSON.stringify(body);
return this;
};
public AddHeader = (name: string, value: string) => {
(this.requestInit.headers as Headers).append(name, value);
return this;
};
public GetTResponseAsync = <T>() => {
return this.rest.GetTResponse<T>(
this.url + this.parameters,
this.requestInit,
);
};
public GetResponseAsync = () => {
return this.rest.GetResponse(this.url + this.parameters, this.requestInit);
};
}
Exception.ts
export enum ErrorLevel {
Error = 1,
Warning = 2,
}
export class RestException extends Error {
readonly Code: string;
readonly Level: ErrorLevel;
readonly Url: string;
readonly Status: number;
readonly MoreDetails: string;
constructor(url: string, status: number, message: string, code?: string, level?: string, moreDetails?: string) {
super(message);
Object.setPrototypeOf(this, RestException.prototype);
this.Code = code;
this.Url = url;
this.Status = status;
this.MoreDetails = moreDetails;
if (level === "WARNING") {
this.Level = ErrorLevel.Warning;
} else {
this.Level = ErrorLevel.Error;
}
}
}