【问题标题】:Retrying requests with axios interceptors and forwarding responses back to frontend使用 axios 拦截器重试请求并将响应转发回前端
【发布时间】:2021-08-16 05:38:34
【问题描述】:

我有一些关于我为一家公司完成的任务的技术问题,以申请初级网络开发人员职位。截止日期已经是二月份了,但我无法及时完成作业。我仍然想完成它,所以我在这里。

首先,我描述了应用程序的目的和功能。它用于为想象中的服装仓库的工人显示产品列表。目前,用户界面有一个包含三个产品类别的下拉菜单:手套、口罩和无檐小便帽。产品列表通过下拉菜单中的选择进行更新。

其次,数据来自两个独立的 API。以下是 API 文档的引用:

GET /v2/products/:category – Return a listing of products in a given category.
GET /v2/availability/:manufacturer – Return a list of availability info.
The APIs are running at https://bad-api-assignment.reaktor.com/.

第一个 API 返回产品数据,例如名称、颜色、价格和制造商。产品可用性数据(有货、缺货等)来自第二个 API。

最后,实际问题。我在处理来自提供可用性数据的 API 的错误响应时遇到问题。该 API 有一个内置的故意失败案例,其中一些响应有一个随机的空数组(通常该数组包含大约 6000 个对象)。我正在考虑在 Node.js 后端处理这个错误案例。下面显示的后端代码仅适用于理想情况,不处理错误情况。

const express = require( 'express' )
const request = require( 'request' )
const app = express()
app.use( express.static( 'build' ))

/* Sets the needed CORS configuration to response header that is sent to the user's browser. */
app.use( ( req, res, next ) => {
    res.header( 'Access-Control-Allow-Origin', '*' )
    next()
} )

/* Forwards the frontend request to Reaktor Bad API server and the response back to frontend.
GET /v2/products/:category – Return a listing of products in a given category: gloves, facemasks or beanies.
GET /v2/availability/:manufacturer – Return a list of availability info.
The APIs are running at https://bad-api-assignment.reaktor.com/. */
app.get( '/api', ( req, res ) => {
    const category = req.query.category
    const manufacturer = req.query.manufacturer
    console.log( 'category query parameter: ', category )
    console.log( 'manufacturer query parameter: ', manufacturer )

    // Reaktor Bad API URL
    const baseUrl = 'https://bad-api-assignment.reaktor.com/v2'

    // craft full URL, make request to Bad API and forward response
    if ( category !== undefined ) {
        request( `${baseUrl}/products/${category}`, ( error, response ) => {
            console.error( 'category error:', error )
            console.log( 'category response & statusCode:', response && response.statusCode )
        } ).pipe( res )
    }
    else if ( manufacturer !== undefined ) {
        request( `${baseUrl}/availability/${manufacturer}`, ( error, response ) => {
            console.error( 'availability error:', error )
            console.log( 'availability response & statusCode:', response && response.statusCode )
        } ).pipe( res )
    }
    else {}
} )

const PORT = process.env.PORT || 3001
app.listen( PORT, () => {
    console.log( `Server running on port ${PORT}` )
} )

如您所见,我正在使用 express 库来指定路线。两个不同的前端请求可以以查询参数的形式到达/api 路由:categorymanufacturer。根据查询参数,将适当的请求发送到 API。此外,路由中使用了现已弃用的请求库。我想用更新的替代品替换它。 request 首先从外部 API 请求数据,然后将其传递给前端。据我了解,这称为反向代理。在前端,我正在等待所有可用性数据到达(使用 axios),然后构建一个包含产品数据和可用性数据的数组。然后将该数组呈现为应用用户界面中显示的产品列表。

我尝试了几种方法来解决这个问题,最近我了解了 axios 拦截器。它们可以用来重试导致错误响应(空数组)的请求吗?如何?反向代理呢?可以用 axios 完成吗?怎么做?我已经阅读了 axios 文档,但没有理解它。使用 express 和 axios 的动机是因为我已经对它们有些熟悉,并且不推荐使用请求库。任何帮助将不胜感激。由于我仍在学习这些东西,因此不仅具有解决方案代码而且还说明其功能的响应对我来说是最有益的。提前谢谢!

【问题讨论】:

    标签: node.js express error-handling axios reverse-proxy


    【解决方案1】:

    我做了一个更简单的,但没有使用 Axios 拦截器,而是重试失败的 Promise,如果你有更复杂的条件,它可以扩展,但基本实现是这样的。

    /**
     * Sleeps for a given number of time
     * @param milliseconds milliseconds to sleep
     * @returns void promise
     */
    export function sleep(milliseconds: number): Promise<void> {
      return new Promise((resolve) => setTimeout(resolve, milliseconds));
    }
    
    /**
     * Wraps a promise like to add retry capability.  This is resursive
     * @param fn promise to wrap
     * @param retries retries remaining
     * @param interval interval between retries
     * @returns promise
     */
    export async function retryable<T>(
      fn: PromiseLike<T>,
      retries: number = 3,
      interval: number = 200
    ): Promise<T> {
      try {
        return await fn;
      } catch (error) {
        if (retries === 0) {
          throw error;
        }
        await sleep(interval);
        return await retryable(fn, retries - 1, interval);
      }
    }
    

    我在 Axios 中拥有的是一个会导致错误的拦截器。这样我就可以在客户端级别模拟故障,而不是在服务器端创建场景。

        if (failureRate > 0) {
          authenticatedClientRef.current.interceptors.request.use((req) => {
            if (Math.random() < failureRate) {
              throw Error('Intentional failure');
            } else {
              return req;
            }
          });
        }
    

    【讨论】:

      猜你喜欢
      • 2020-09-25
      • 2020-10-22
      • 2020-11-21
      • 2021-08-06
      • 2020-02-12
      • 2022-11-14
      • 1970-01-01
      • 1970-01-01
      • 2019-01-04
      相关资源
      最近更新 更多