UNPKG

http-svc

Version:

A HTTP request service for browser and node.js

212 lines (193 loc) 6.04 kB
import { BuiltInMiddleware, BuiltInMiddlewareName, IHttpSvcContext } from 'types/exports' import qs, { IStringifyOptions } from 'qs' export const getBuiltInMiddlewareName = (name: BuiltInMiddleware): BuiltInMiddlewareName => `BUILT_IN_${name}` export const isMiddleware = (middleware: any) => { if ((middleware as any).name && (middleware as any).handler) return true return false } interface IHttpSvcError extends Error { config?: IHttpSvcContext['config'] response?: IHttpSvcContext['response'] status?: number [key: string]: any } export const createDefaultError = (ctx: IHttpSvcContext, message?: string): IHttpSvcError => { const status = ctx.response?.status const def = 'Request Error' let msg = '' if (message) { msg = message } else if (typeof status === 'number') { msg = `${def}: ${status}` } else { msg = def } return new Error(msg) as IHttpSvcError } /** * 创建error * e 可以是 Error | string | 或者对象上可访问message属性的对象 */ export const createError = (ctx: IHttpSvcContext, e?: any): IHttpSvcError => { let error: IHttpSvcError if (typeof e === 'undefined') { error = createDefaultError(ctx) } else { if (e instanceof Error) { error = e as IHttpSvcError } else { error = createDefaultError(ctx, typeof e === 'string' ? e : e?.message) } } const status = ctx.response?.status if (ctx.request) { error.config = { url: ctx.request.url!, method: ctx.request.method!, params: ctx.request.params!, data: ctx.request.data!, headers: ctx.request.headers! } } else { error.config = ctx.config } if (ctx.response) { error.response = ctx.response if (!ctx.response.ok && status) { error.status = status } } return error } export const isNode: boolean = typeof window === 'undefined' export const isArray = (val: any) => toString.call(val) === '[object Array]' export const isObject = (val: any) => val !== null && typeof val === 'object' export const isRecordObj = (obj: any) => Object.prototype.toString.call(obj) === '[object Object]' export const isFormData = (val: any) => typeof FormData !== 'undefined' && val instanceof FormData export const paramsSerializer = (params: Record<string, unknown>, options?: IStringifyOptions) => { return qs.stringify( params, options || { encode: true, arrayFormat: 'brackets' } ) } export const buildURL = ( url: string, params: { [x: string]: unknown }, ps?: ((params: Record<string, unknown>) => string) | IStringifyOptions ): string => { let serializedParams = '' if (Object.keys(params).length === 0) { return url } if (typeof ps === 'function') { serializedParams = ps(params) } else { const qsOptions: IStringifyOptions = { encode: true, arrayFormat: 'brackets' } if (ps && typeof ps === 'object') { Object.assign(qsOptions, ps) } serializedParams = paramsSerializer(params, qsOptions) } if (serializedParams) { const hashMarkIndex = url.indexOf('#') if (hashMarkIndex !== -1) { url = url.slice(0, hashMarkIndex) as string } url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams } return url } export const parseURL = (url: string): { url: string; params?: Record<string, string> } => { const [u, s] = url.split('?') if (s) { const searchParams = s.split('&') if (searchParams.length) { const params: Record<string, string> = {} for (const searchParam of searchParams) { const [key, value] = searchParam.split('=') if (key && typeof value !== 'undefined') { params[key] = value } } return { url: u, params } } } return { url } } export const formatString = (input: string) => { let afterFormat = '' for (let i = 0; i < input.length; i++) { afterFormat += String.fromCharCode(input.charCodeAt(i) - 1) } return afterFormat } // 标准的content-type key写法 const CONTENT_TYPE_KEY = 'Content-Type' export enum ContentType { JSON = 'application/json', Form = 'application/x-www-form-urlencoded', FormData = 'multipart/form-data' } export const isEqualContentType = (target: string, current?: string) => { if (!current) return false return current.indexOf(target) > -1 } // 从headers里取contenttype export const getContentType = (headers?: Record<string, string>) => headers?.[CONTENT_TYPE_KEY] || headers?.['content-type'] // 非标准写法 export const setContentType = (headers: Record<string, string>, contentType: string) => { if (!contentType) return headers[CONTENT_TYPE_KEY] = contentType } export const getCookie = (key: string, options?: { decode?: boolean; template?: string }) => { if (!options) options = {} const isNoDecode = options.decode === false const template = options.template || document.cookie const decodedCookie = isNoDecode ? template : decodeURIComponent(template) const cookies = decodedCookie.split(';') for (let i = 0; i < cookies.length; i++) { let cookie = cookies[i] while (cookie.charAt(0) === ' ') { cookie = cookie.substring(1) } const keyVal = cookie.split('=') const name = keyVal[0] const value = keyVal[1] if (key === name) return value } return '' } export const setObjectValue = (obj: Record<string, any>, keyOrKeys: string | string[], value: any, spread?: boolean): void => { if (Array.isArray(keyOrKeys)) { const keys = [...keyOrKeys] while (keys.length) { if (keys.length === 1) { setObjectValue(obj, keys[0], value) break } const key = keys.shift() as string if (!isRecordObj(obj)) { if (typeof obj[key] === 'undefined' && spread) { obj[key] = {} } else { console.warn(`The value of "${key}" is not a record object!`) break } } obj = obj[key] } } else { const key = keyOrKeys obj[key] = value } }