import fetch from 'cross-fetch' ; import { RequestBodyType , RequestFunctionParams } from 'yapi-to-typescript' ; export interface RequestOptions { /**
     * 是否返回 Blob 结果，适用某些返回文件流的接口。
     */ returnBlob ? : boolean ; } export enum RequestErrorType { NetworkError = 'NetworkError' , StatusError = 'StatusError' , BusinessError = 'BusinessError' } export class RequestError extends Error { constructor ( public type , public message , public httpStatusOrBusinessCode = 0 ) { super ( message instanceof Error ? message . message : String ( message ) ) ; } } export default async function request < TResponseData > ( payload , options ? ) { try { const baseUrl = payload . prodUrl ; const url = `${ baseUrl }${ payload . path }` ; const fetchOptions = { method : payload . method , headers : { ... ( payload . hasFileData ? { } : payload . requestBodyType === RequestBodyType . json ? { 'Content-Type' : 'application/json; charset=UTF-8' } : payload . requestBodyType === RequestBodyType . form ? { 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8' , } : { } ) , } , body : payload . hasFileData ? payload . getFormData ( ) : payload . requestBodyType === RequestBodyType . json ? JSON . stringify ( payload . data ) : payload . requestBodyType === RequestBodyType . form ? Object . keys ( payload . data ) . filter ( key => payload . data [ key ] != null ) . map ( key => `${ encodeURIComponent ( key ) }=${ encodeURIComponent ( payload . data [ key ] ) }` ) . join ( '&' ) : undefined , } ; const [ fetchErr , fetchRes ] = await fetch ( url , fetchOptions ) . then < [ TypeError , Response ] > ( res => [ null , res ] as any , err => [ err , null ] as any ) ; if ( fetchErr ) { throw new RequestError ( RequestErrorType . NetworkError , fetchErr ) ; } if ( fetchRes . status < 200 || fetchRes . status >= 300 ) { throw new RequestError ( RequestErrorType . StatusError , `${ fetchRes . status }: ${ fetchRes . statusText }` , fetchRes . status ) ; } const res = options ?. returnBlob ? await fetchRes . blob ( ) : ( fetchRes . headers . get ( 'Content-Type' ) || '' ) . indexOf ( 'application/json' ) >= 0 ? await fetchRes . json ( ) . catch ( ( ) => ( { } ) ) : await fetchRes . text ( ) ; if ( res != null && typeof res === 'object' && res . code != null && res . code !== 0 ) { throw new RequestError ( RequestErrorType . BusinessError , res . msg , res . code ) ; } const data = res != null && typeof res === 'object' && payload . dataKey != null && res [ payload . dataKey ] != null ? res [ payload . dataKey ] : res ; return data ; } catch ( err ) { const retry = ( ) => request < TResponseData > ( payload , options ) ; if ( err instanceof RequestError ) { if ( err . type === RequestErrorType . NetworkError ) { const isRetry = confirm ( `网络错误：${ err . message }，是否重试？` ) ; if ( isRetry ) { return retry ( ) ; } throw err ; } else if ( err . type === RequestErrorType . StatusError ) { if ( err . httpStatusOrBusinessCode === 401 ) { } } else if ( err . type === RequestErrorType . BusinessError ) { throw err ; } } else { throw err ; } } }