Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with POST-requests using routeRules in h3 > 1.7.1 #510

Closed
ahoiroman opened this issue Aug 17, 2023 · 7 comments
Closed

Problems with POST-requests using routeRules in h3 > 1.7.1 #510

ahoiroman opened this issue Aug 17, 2023 · 7 comments

Comments

@ahoiroman
Copy link

Environment

Reproduction

As stated at nuxt/nuxt#22645, I got an issue sending POST requests to proxied routes (routeRules with proxy).

routeRules: {
        '/api/v1/**': {
            proxy: `${process.env.NUXT_PUBLIC_BACKEND_URL}/api/${process.env.NUXT_PUBLIC_API_VERSION}/**`,
        },
        '/web/**': {
            proxy: `${process.env.NUXT_PUBLIC_BACKEND_URL}/**`,
        },
        '/csrf': {
            proxy: `${process.env.NUXT_PUBLIC_BACKEND_URL}/sanctum/csrf-cookie`,
        },
    },

The error only occurs, when these criteria are matched:

  • h3 > 1.7.1 is installed. Pinning h3 to 1.7.1 fixes the problem
  • Type of request is POST
  • Post request contains a body - without body, the error does not occur (but - of course - the request is quite useless)

Describe the bug

The following error is thrown:

[nuxt] [request error] [unhandled] [500] fetch failed (http://api.app.test/auth/login)
  at async sendProxy (./node_modules/h3/dist/index.mjs:1017:20)  
  at async Object.handler (./node_modules/h3/dist/index.mjs:1683:19)  
  at async Server.toNodeHandle (./node_modules/h3/dist/index.mjs:1893:7)

Sending a CURL request gives the same result:

curl 'http://web.app.test/web/auth/login' \
-X 'POST' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: de-DE,de;q=0.9' \
-H 'Host: web.app.test' \
-H 'Origin: http://web.app.test' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15' \
-H 'Connection: keep-alive' \
-H 'Referer: http://web.app.test/auth/signin' \
-H 'Content-Length: 48' \
-H 'Cookie: XSRF-TOKEN=...%3D; laravel_session=...%3D; i18n_redirected=en-US' \
-H 'x-xsrf-token: ...=' \
--data-binary '{"email":"[email protected]","password":"secret"}'

Additional context

Utility used to make requests to Laravel:

export async function $larafetch<T, R extends ResponseType = "json">(
    path: RequestInfo,
    {
        redirectIfNotAuthenticated = true,
        redirectIfNotVerified = true,
        useApiMiddleware = true,
        ...options
    }: LarafetchOptions<R> = {}
) {
    const {frontendUrl, apiVersion} = useRuntimeConfig().public
    const backendUrl = useApiMiddleware ? `${frontendUrl}/api/${apiVersion}` : `${frontendUrl}/web/`
    const router = useRouter()

    let token = useCookie(CSRF_COOKIE).value

    // on client initiate a csrf request and get it from the cookie set by laravel
    if (
        process.client &&
        ["post", "delete", "put", "patch"].includes(
            options?.method?.toLowerCase() ?? ""
        )
    ) {
        await initCsrf()
        token = useCookie('XSRF-TOKEN')?.value
    }

    let headers: any = {
        accept: "application/json",
        ...options?.headers,
        ...(token && {[CSRF_HEADER]: token}),
    }

    if (process.server) {
        headers = {
            ...headers,
            ...useRequestHeaders(["cookie"]),
            referer: frontendUrl,
        }
    }

    try {
        return await $fetch<T, R>(path, {
            baseURL: backendUrl,
            ...options,
            headers,
            credentials: "include",
        })
    } catch (error) {
        if (!(error instanceof FetchError)) throw error

        // when any of the following redirects occur and the final throw is not caught then nuxt SSR will log the following error:
        // [unhandledRejection] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

        const status = error.response?.status ?? -1

        if (redirectIfNotAuthenticated && [401, 419].includes(status)) {
            await router.push("/login")
        }

        if (redirectIfNotVerified && [409].includes(status)) {
            await router.push("/verify-email")
        }

        if ([500].includes(status)) {
            console.error("[Error]", error.data?.message, error.data)
        }

        throw error
    }
}

Logs

No response

@danielkuzela
Copy link

danielkuzela commented Aug 22, 2023

I am having same trouble. Upgrading from 1.7.1 to 1.8.0 breaks it even more.
When I send POST request via proxy, it goes through. If I include file, I get same error:

  at async sendProxy (./node_modules/.pnpm/[email protected]/node_modules/h3/dist/index.mjs:521:20)  
  at async Object.handler (./node_modules/.pnpm/[email protected]/node_modules/h3/dist/index.mjs:1284:19)  
  at async Server.toNodeHandle (./node_modules/.pnpm/[email protected]/node_modules/h3/dist/index.mjs:1359:7)

@gzf6
Copy link

gzf6 commented Aug 24, 2023

same issue when upgrading from 1.7.1 to 1.8.0

@pi0
Copy link
Member

pi0 commented Aug 26, 2023

Hi. Sorry for the inconvenience with upgrading.

Since there is no minimal reproduction, I cannot confirm if unjs/ofetch#269 > unjs/ofetch#273 solved the same issue as you had but it seems was related (as you seem using proxy rules which was using ofetch as well) it would be nice if you could try to refresh your lockfile with latest dependencies to see if a problem exists.

In case it still exists, and you can make a reproduction, please consider making a new issue in nuxt repository and ping me to investigate 🙏🏼

@pi0 pi0 closed this as completed Aug 26, 2023
@danielkuzela
Copy link

danielkuzela commented Aug 30, 2023

@ahoiroman I just updated to Nuxt 3.7.0 which uses [email protected] and my problem was solved, maybe you could give it a try, but my problem was only with files, other way it worked

@ahoiroman
Copy link
Author

Yep, works with Nuxt ^3.7. Thanks :-)

@ahoiroman
Copy link
Author

Please reopen, this does not work when it comes to DELETE requests.

@ahoiroman
Copy link
Author

@pi0: As I found out, this happens, if the DELETE request, which is being made, does not have a body.

If you add an empty body, it works as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants