feat(project): init
This commit is contained in:
295
api/fetch.ts
Normal file
295
api/fetch.ts
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
|
||||
Fetch 接口
|
||||
fetch() 包含了 fetch() 方法,用于获取资源。
|
||||
Headers 表示响应/请求的标头信息,允许你查询它们,或者针对不同的结果做不同的操作。
|
||||
Request 相当于一个资源请求。
|
||||
Response 相当于请求的响应
|
||||
|
||||
fetch 参数:
|
||||
method: 请求使用的方法,如 GET、POST。
|
||||
headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量
|
||||
body: 请求的 body 信息:可能是一个 Blob、BufferSource(x禁止)、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
|
||||
mode: 请求的模式,如 cors、no-cors 或者 same-origin。
|
||||
credentials: 请求的 credentials,如 omit、same-origin 或者 include。为了在当前域名内自动发送 cookie,必须提供这个选项,从 Chrome 50 开始,这个属性也可以接受 FederatedCredential (en-US) 实例或是一个 PasswordCredential (en-US) 实例。
|
||||
|
||||
*/
|
||||
"use client"
|
||||
|
||||
import { useUserStore } from "@/app/store/user"
|
||||
import { deleteCookie, refreshKey } from "@/components/login/api"
|
||||
import { isNumber } from "@/libs/util"
|
||||
|
||||
interface OptionsProps {
|
||||
url: string
|
||||
method: string
|
||||
body?: BodyInit
|
||||
data?: any
|
||||
needCredentials?: boolean
|
||||
isUpload?: boolean
|
||||
isDownload?: boolean
|
||||
isFormData?: boolean
|
||||
isLogin?: boolean
|
||||
isRefresh?: boolean
|
||||
isDeleteCookie?: boolean
|
||||
notJson?: boolean
|
||||
headerAttr?: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
|
||||
async function httpfetch<T>(options: OptionsProps): Promise<T> {
|
||||
const { removeUserInfo, refreshToken } = useUserStore.getState()
|
||||
|
||||
const access_token = useUserStore.getState().access_token
|
||||
const refresh_token = useUserStore.getState().refresh_token
|
||||
|
||||
let Message = {
|
||||
error: (params: { content: string }) => {
|
||||
console.log(params.content)
|
||||
},
|
||||
}
|
||||
|
||||
const createSsrRequest: (options: OptionsProps, token?: string) => Request = (
|
||||
options
|
||||
) => {
|
||||
// 设置请求头
|
||||
let myHeaders = new Headers()
|
||||
if (!options.isUpload && !options.isFormData && !options.notJson) {
|
||||
myHeaders.append("Content-Type", "application/json")
|
||||
}
|
||||
if (options.isDownload) {
|
||||
myHeaders.append("Response-Type", "blob")
|
||||
}
|
||||
if (options.isFormData) {
|
||||
options.body &&
|
||||
(options.body as FormData)?.append &&
|
||||
(options.body as FormData).append("options", JSON.stringify(options))
|
||||
}
|
||||
|
||||
// 配置常用设置 method 请求方式 headers 请求头
|
||||
let myInit: RequestInit = {
|
||||
method: "POST",
|
||||
headers: myHeaders,
|
||||
mode: "cors",
|
||||
cache: "default",
|
||||
body: options.isFormData
|
||||
? options.body
|
||||
: (JSON.stringify({ data: options.body, ...options }) as BodyInit),
|
||||
}
|
||||
const pathList = options.url.split("/")
|
||||
const request = new Request(
|
||||
`/api/${options.isFormData ? "transferFormData" : "transfer"}/${pathList[pathList.length - 1]}`,
|
||||
myInit
|
||||
)
|
||||
return request
|
||||
}
|
||||
|
||||
const createCsrRequest: (options: OptionsProps, token?: string) => Request = (
|
||||
options,
|
||||
token = ""
|
||||
) => {
|
||||
let request = new Request(options.url)
|
||||
// 设置请求头
|
||||
let myHeaders = new Headers()
|
||||
myHeaders.append("Authorization", `bearer ${token}`)
|
||||
if (!options.isUpload && !options.isFormData && !options.notJson) {
|
||||
myHeaders.append("Content-Type", "application/json")
|
||||
}
|
||||
if (options.isDownload) {
|
||||
myHeaders.append("Response-Type", "blob")
|
||||
}
|
||||
if (options.headerAttr) {
|
||||
Object.entries(options.headerAttr).map(([key, value]) => {
|
||||
myHeaders.append(key, value)
|
||||
})
|
||||
}
|
||||
// myHeaders.append("X-Machine-Code", "machine_code0")
|
||||
|
||||
// 配置常用设置 method 请求方式 headers 请求头
|
||||
let myInit: RequestInit = {
|
||||
method: options.method,
|
||||
headers: myHeaders,
|
||||
mode: "cors",
|
||||
cache: "default",
|
||||
credentials: options.needCredentials ? "include" : undefined,
|
||||
body: options.body as BodyInit,
|
||||
}
|
||||
|
||||
let publicUrl = options.url.includes("http")
|
||||
? ""
|
||||
: process.env.NEXT_PUBLIC_URL
|
||||
if (options.method === "GET") {
|
||||
let searchParams = new URLSearchParams()
|
||||
Object.entries(options.data || {})?.map((m) => {
|
||||
searchParams.append(m[0], m[1] as string)
|
||||
})
|
||||
let concatenatedURL = searchParams.toString()
|
||||
? options.url + "?" + searchParams.toString()
|
||||
: options.url
|
||||
request = new Request(publicUrl + concatenatedURL, myInit)
|
||||
} else {
|
||||
request = new Request(publicUrl + options.url, myInit)
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
const createNewRequest =
|
||||
process.env.NEXT_PUBLIC_OUTPUT_TYPE === "standalone"
|
||||
? createSsrRequest
|
||||
: createCsrRequest
|
||||
|
||||
const request = createNewRequest(options, access_token)
|
||||
|
||||
return new Promise((resolved, rejected) => {
|
||||
fetch(request)
|
||||
.then(async (response) => {
|
||||
if (response.status === 200) {
|
||||
if (options.isDownload) {
|
||||
return response.blob()
|
||||
} else {
|
||||
return response.headers
|
||||
.get("Content-Type")
|
||||
?.includes("application/json")
|
||||
? response.json()
|
||||
: response.text()
|
||||
}
|
||||
} else {
|
||||
const { status } = response
|
||||
|
||||
if (status === 400) {
|
||||
if (
|
||||
response.headers.get("Content-Type")?.includes("application/json")
|
||||
) {
|
||||
const data = await response.json()
|
||||
const { message: errInfo } = data
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
} else {
|
||||
const errInfo = await response.text()
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
}
|
||||
} else if (status === 403) {
|
||||
if (
|
||||
response.headers.get("Content-Type")?.includes("application/json")
|
||||
) {
|
||||
const data = await response.json()
|
||||
const { message: errInfo } = data
|
||||
Message.error({ content: errInfo || "" })
|
||||
location.href = `${process.env.NEXT_PUBLIC_HOME_URL}`
|
||||
throw new Error(errInfo)
|
||||
} else {
|
||||
const errInfo = await response.text()
|
||||
Message.error({ content: errInfo || "" })
|
||||
location.href = `${process.env.NEXT_PUBLIC_HOME_URL}`
|
||||
throw new Error(errInfo)
|
||||
}
|
||||
} else if (status === 500) {
|
||||
if (
|
||||
response.headers.get("Content-Type")?.includes("application/json")
|
||||
) {
|
||||
const data = await response.json()
|
||||
const { message: errInfo } = data
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
} else {
|
||||
const errInfo = await response.text()
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
}
|
||||
} else if (status === 406) {
|
||||
const data = await response.json()
|
||||
const { message: errInfo } = data
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
} else if (status >= 510) {
|
||||
Message.error({ content: "申请资源不足!" })
|
||||
throw new Error("申请资源不足!")
|
||||
} else {
|
||||
Message.error({ content: "网络服务有误!" })
|
||||
throw new Error("Something went wrong on API server!")
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(async (response) => {
|
||||
const { code, message: errInfo } = response
|
||||
if (response) {
|
||||
if (isNumber(code)) {
|
||||
let status = code
|
||||
// 日后做相关处理
|
||||
if (status === 401) {
|
||||
try {
|
||||
const refreshResponse = await refreshKey({
|
||||
token: refresh_token,
|
||||
})
|
||||
if (refreshResponse.code === 200) {
|
||||
let access_token = refreshResponse.message?.access || ""
|
||||
let refresh_token = refreshResponse.message?.refresh || ""
|
||||
refreshToken({
|
||||
refresh_token,
|
||||
access_token,
|
||||
})
|
||||
const retry_request = createNewRequest(options, access_token)
|
||||
const retry_response = await fetch(retry_request)
|
||||
return options.isDownload
|
||||
? retry_response.blob()
|
||||
: retry_response.json()
|
||||
} else {
|
||||
const { code } = refreshResponse
|
||||
if (code === 406) {
|
||||
try {
|
||||
await deleteCookie()
|
||||
} catch (error) {
|
||||
rejected(error)
|
||||
} finally {
|
||||
// 清空身份信息并跳转至登录页面
|
||||
removeUserInfo()
|
||||
window.location.href = "/login"
|
||||
}
|
||||
} else {
|
||||
throw new Error("重新获取token失败!")
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
rejected(error)
|
||||
}
|
||||
} else if (status === 400) {
|
||||
const { message: errInfo } = response
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
} else if (status === 403) {
|
||||
const { message: errInfo } = response
|
||||
Message.error({ content: errInfo || "" })
|
||||
// location.href = `${process.env.NEXT_PUBLIC_HOME_URL}`
|
||||
throw new Error(errInfo)
|
||||
} else if (status === 500) {
|
||||
const { message: errInfo } = response
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
} else if (status === 406) {
|
||||
const { message: errInfo } = response
|
||||
Message.error({ content: errInfo || "" })
|
||||
throw new Error(errInfo)
|
||||
} else if (status >= 510) {
|
||||
Message.error({ content: "申请资源不足!" })
|
||||
throw new Error("申请资源不足!")
|
||||
} else if (status === 200) {
|
||||
resolved(response)
|
||||
} else {
|
||||
Message.error({ content: "网络服务有误!" })
|
||||
throw new Error("Something went wrong on API server!")
|
||||
}
|
||||
}
|
||||
resolved(response)
|
||||
} else {
|
||||
throw new Error(errInfo)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
rejected(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default httpfetch
|
||||
30
api/typing.ts
Normal file
30
api/typing.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
// * 请求响应参数(不包含data)
|
||||
export interface Result {
|
||||
code: number
|
||||
status: boolean
|
||||
}
|
||||
// * 请求响应参数(包含data)
|
||||
export interface ResultDataList<T = any> extends Result {
|
||||
data: T[]
|
||||
}
|
||||
|
||||
export interface ResultData<T = any> extends Result {
|
||||
message: T
|
||||
}
|
||||
|
||||
export interface ResultList<T = any> extends Result {
|
||||
list: T
|
||||
}
|
||||
|
||||
export interface ResPage<T> {
|
||||
list: T[]
|
||||
page_number?: number
|
||||
page_size?: number
|
||||
total: number
|
||||
total_pages?: number
|
||||
}
|
||||
|
||||
export interface ReqPage {
|
||||
page_num?: number
|
||||
page_size?: number
|
||||
}
|
||||
Reference in New Issue
Block a user