Diseño AOP en el marco de front-end

Diseño AOP en el marco de front-end

Que es AOP

AOP es un paradigma de programación orientado al aspecto de procesos de negocio. La idea de utilizar AOP puede aislar cada módulo de lógica de negocio, reducir el acoplamiento entre cada módulo y aumentar la reutilización. AOP no especifica la implementación específica de su protocolo. Realice su propias necesidades.

Por ejemplo, filtros globales de front-end comunes, interfaces de back-end de solicitud, mapeo de datos globales, procesamiento de estado intermedio, etc., abstraen una cierta etapa de la lógica comercial lineal como un módulo independiente y cortan en más cadenas de llamadas cuando sea apropiado. El camino

Inserte la descripción de la imagen aquí

Cómo realizar el pensamiento AOP en el marco de front-end

Tome una solicitud http como ejemplo. Por ejemplo, el siguiente código contiene el procesamiento del encabezado de la solicitud, la conversión de los datos, la adición del nombre de dominio solicitado y el procesamiento de la respuesta.

async function requestAPI(url: string, init: RequestInit) {
    
    
  init.headers = init.headers ?? {
    
    }
  init.headers = {
    
     'contentType': 'application/x-www-form-urlencoded; charset=UTF-8', ...init.headers }
  if (init.body === 'object' && !Array.isArray(init.body)) {
    
    
    init.body = JSON.stringify(init.body ?? {
    
    })
  }
  const regex = new RegExp('(^https:)|(^http:)\/\/([^\/\?]+)', 'g')
  if (!regex.test(url)) {
    
    
    url = 'https:xxx.com' + url
  }
  try {
    
    
    const response = await fetch(url, init)
    const res = await response.json()
    if (res.code === 200) {
    
    
      return res.data
    } else {
    
    
      throw new ApiException({
    
    
        code: res.code,
        msg: res.msg,
        url
      })
    }
  } catch (error) {
    
    
    if (error instanceof ApiException) {
    
    
      throw error
    }
    // ...处理异常
  }
}

De esta manera, si es necesario ajustar el encabezado de la solicitud y se requiere algún procesamiento de los parámetros o respuestas de la solicitud, se debe construir un nuevo método de solicitud o se requieren algunas modificaciones al método original, y el procesamiento, como la limitación y También se necesita anti-vibración Si esta función se modifica o encapsula aquí, ¿cómo debería implementarse con la idea de AOP?


interface HttpOption extends RequestInit {
    
    
  url: string
  body?: any
}

interface HttpResponse<T> {
    
    
  code: number
  data: T
  msg: string
}

function DomainDecorators() {
    
    
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    
    
    const fn = descriptor.value as (options: HttpOption) => Promise<Response>
    descriptor.value = (options: {
    
    
      domain: string
    } & HttpOption) => {
    
    
      if (options?.domain) {
    
    
        const regex = new RegExp('(^https:)|(^http:)\/\/([^\/\?]+)', 'g')
        if (!regex.test(options.url)) {
    
    
          options.url = options.domain + options.url
        }
      }
      return fn.call(target, options)
    }
  }
}

function OptionsDecorators() {
    
    
  return function (target: HttpClient, propertyKey: string, descriptor: PropertyDescriptor) {
    
    
    const fn = descriptor.value as (options: HttpOption) => Promise<Response>
    descriptor.value = (options: HttpOption) => {
    
    
      options.headers = {
    
     'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', ...options.headers }
      if (options.body === 'object' && !Array.isArray(options.body)) {
    
    
        options.body = JSON.stringify(options.body ?? {
    
    })
      }
      return fn.call(target, options)
    }
  }
}

function ExceptionDecorators() {
    
    
  return function (target: HttpClient, propertyKey: string, descriptor: PropertyDescriptor) {
    
    
    const fn = descriptor.value as (options: HttpOption) => Promise<HttpResponse<any>>
    descriptor.value = async (options: HttpOption) => {
    
    
      const res = await fn.call(target, options)
      if (res.code === 200) {
    
    
        return res.data
      } else {
    
    
        throw new ApiException({
    
    
          code: res.code,
          msg: res.msg,
          url: options.url
        })
      }
    }
  }
}


abstract class HttpBase {
    
    
  get options(): {
    
    
    domain?: string
  } & RequestInit {
    
    
    return {
    
    
      mode: 'cors',
      credentials: 'include',
      cache: 'no-cache',
      redirect: 'follow'
    }
  }
  post<T>(options: HttpOption): Promise<HttpResponse<T>> {
    
    
    options.method = 'POST'
    return fetch(options.url, options).then((res) => res.json())
  }
  get<T>(options: HttpOption): Promise<HttpResponse<T>> {
    
    
    options.method = 'GET'
    return fetch(options.url, options).then((res) => res.json())
  }
}

class HttpClient extends HttpBase {
    
    
  @DomainDecorators()
  @OptionsDecorators()
  @ExceptionDecorators()
  post<T>(options: HttpOption): Promise<HttpResponse<T>> {
    
    
    return super.post(options)
  }
}

Aquí podemos abstraer la parte de procesamiento del encabezado de la solicitud y la parte correspondiente, a medida que un aspecto se entrelaza con la clase de solicitud implementada, separar el procesamiento de parámetros, la adición de nombre de dominio y las excepciones de respuesta, y ensamblarlos cuando sea necesario. Cada módulo sirve a la solicitud , pero no hay asociación o dependencia antes, siempre que la firma del método del objeto decorado sea la misma, entonces estas funciones se reutilizan ~

Supongo que te gusta

Origin blog.csdn.net/vipshop_fin_dev/article/details/113126337
Recomendado
Clasificación