unjs / nitro

Next Generation Server Toolkit. Create web servers with everything you need and deploy them wherever you prefer.
https://nitro.unjs.io
MIT License
5.59k stars 482 forks source link

swr + proxy requests #2109

Open AndersCV opened 6 months ago

AndersCV commented 6 months ago

Environment


Reproduction

https://stackblitz.com/edit/nuxt-starter-51fgbr

Describe the bug

When proxying api requests through Nitro that have caching enabled from routeRules the response object is malformed. In the reproduction i linked I'm using a catch-all endpoint to proxy requests from Nitro to an external backend. With caching enabled the response returned from this endpoint is malformed.

Happens when using the h3 proxyRequest method. Switching to $fetch resolves the issue.

Additional context

No response

Logs

No response

manniL commented 6 months ago

As a workaround: Using $fetch to get the data, then transform + return should still work fine with SWR/caching rules

dennisadriaans commented 2 months ago

@manniL Could you provide some additional information on your workaround? We'd also like to implement caching for proxy calls.

We're currently using Nuxt with a custom server route that functions as a proxy for an useFetch requests. Within the custom server route, we return a cachedEventHandler that calls the API.

We'd like to change that to use routeRules with a proxy handler and caching options.

AndersCV commented 2 months ago

@dennisadriaans

I came up with this catch-all route to proxy all my requests to external backend:

// server/api/[...].ts

import { joinURL } from 'ufo'

export default defineEventHandler(async (event) => {
  const proxyUrl = useRuntimeConfig().proxyUrl
  const secretKey = useRuntimeConfig().apiToken
  const authHeaderName = useRuntimeConfig().public.AUTH_HEADER_NAME

  const path = event.path.replace(/^\/api\//, '')
  const target = joinURL(proxyUrl, path)
  const method = event.method
  const authHeader = getHeader(event, authHeaderName)

  // readBody inside a GET request returns 405 so we have to check request method
  const body = method !== 'GET' ? await readBody(event) : null

  try {
    return await $fetch(target, {
      method: method,
      body: body,
      headers: {
        'X-TBOOK-TOKEN': secretKey,
        ...(authHeader && { [authHeaderName]: authHeader }),
      },
    })
  } catch (error) {
    throw createError(error as Error)
  }
})