Skip to content

[bug]: Next.js Server Components - Missing Headers in Outbound RequestsΒ #54

@linxiang-dev

Description

@linxiang-dev

Bug Description

Hi community!

I'm encountering a very strange issue with Next.js Server Components and the official Strapi JS library (@strapi/sdk-js). When I make requests to my Strapi backend from within a Server Component using the Strapi JS library, the Content-Type and Authentication headers are mysteriously missing in the outbound request. This results in a 403 error from Strapi.

Here's the breakdown of what I've observed:

Server Components + Strapi JS Library: Headers (Content-Type, Authentication) are missing in the request. Strapi returns 403.

Client Components + Strapi JS Library: Headers are present, request is successful, Strapi works as expected.

Direct Node.js script (using this demo outside Next.js) + Strapi JS Library: Headers are present, request is successful, Strapi works as expected.

Server Components + fetch or axios: Headers are present, request is successful, Strapi works as expected.

This isolates the issue specifically to the combination of Next.js Server Components and the Strapi JS library. It's not a general networking problem in Server Components because fetch and axios work fine. It's also not a fundamental issue with the Strapi JS library itself, as it works in other contexts.

Steps to Reproduce

Steps to Reproduce

  1. clone this simple demo repo: https://github.com/DebugNinjaSlayer/missing-header-demo
  2. yarn
  3. yarn dev
  4. access http://127.0.0.1:3000
  5. there should be error logs on server like this
Running with api token e4525f6cb23fd4c477b0071d067b31701f481678d1f022bf3eddbffb3e3494830cfe5feab5fa09f7a33ecd27b105a20bd22f3028250afb67dad85770f7e687b5b3e0697e4a3eac4362782d074157521c78512d9d2d1b4900b072813942eabf991addfa9ba5c35c530b3949e0dd05a64296eadca877cdc2360b54609e3529c470
Error [HTTPForbiddenError]: Request failed with status code 403 Forbidden: GET http://localhost:1337/api/categories
    at <unknown> (HTTPForbiddenError: Request failed with status code 403 Forbidden: GET http://localhost:1337/api/categories)
    at async Home (src/app/page.tsx:17:17)
  15 |     const categories = sdk.collection("categories");
  16 |
> 17 |     const docs = await categories.find();
     |                 ^
  18 |     console.dir(docs, { depth: null });
  19 |   } catch (error) {
  20 |     console.log(error); {
  response: Response {
    status: 403,
    statusText: 'Forbidden',
    headers: Headers {
      'content-security-policy': "connect-src 'self' https:;img-src 'self' data: blob: market-assets.strapi.io course-hosting-kit-dev.ccdf58dba7baa04c265641c25962951d.r2.cloudflarestorage.com;media-src 'self' data: blob: market-assets.strapi.io course-hosting-kit-dev.ccdf58dba7baa04c265641c25962951d.r2.cloudflarestorage.com;frame-src 'self' youtube.com www.youtube.com vimeo.com *.vimeo.com facebook.com www.facebook.com course-hosting-kit-dev.ccdf58dba7baa04c265641c25962951d.r2.cloudflarestorage.com;default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline'",
      'referrer-policy': 'no-referrer',
      'strict-transport-security': 'max-age=31536000; includeSubDomains',
      'x-content-type-options': 'nosniff',
      'x-dns-prefetch-control': 'off',
      'x-download-options': 'noopen',
      'x-frame-options': 'SAMEORIGIN',
      'x-permitted-cross-domain-policies': 'none',
      vary: 'Origin',
      'access-control-allow-origin': '',
      'access-control-allow-credentials': 'true',
      'content-type': 'application/json; charset=utf-8',
      'x-powered-by': 'Strapi <strapi.io>',
      'content-length': '95',
      date: 'Wed, 12 Feb 2025 06:50:10 GMT',
      connection: 'keep-alive',
      'keep-alive': 'timeout=5'
    },
    body: undefined,
    bodyUsed: false,
    ok: false,
    redirected: false,
    type: 'basic',
    url: 'http://localhost:1337/api/categories'
  },
  request: Request {
    method: 'GET',
    url: 'http://localhost:1337/api/categories',
    headers: Headers {
      'Content-Type': 'application/json',
      Authorization: 'Bearer e4525f6cb23fd4c477b0071d067b31701f481678d1f022bf3eddbffb3e3494830cfe5feab5fa09f7a33ecd27b105a20bd22f3028250afb67dad85770f7e687b5b3e0697e4a3eac4362782d074157521c78512d9d2d1b4900b072813942eabf991addfa9ba5c35c530b3949e0dd05a64296eadca877cdc2360b54609e3529c470'
    },
    destination: '',
    referrer: 'about:client',
    referrerPolicy: '',
    mode: 'cors',
    credentials: 'same-origin',
    cache: 'default',
    redirect: 'follow',
    integrity: '',
    keepalive: false,
    isReloadNavigation: false,
    isHistoryNavigation: false,
    signal: [AbortSignal]
  }
}
 GET / 200 in 142ms
 GET /favicon.ico?favicon.45db1c09.ico 200 in 23ms

It's worthy noting that there are Authorization header in the error log but when capturing requests with Wireshark, the headers are actually missing

I also created a repo shows it works well with client component https://github.com/DebugNinjaSlayer/client-component-demo

Expected Behavior

Given these observations, I'm wondering if there's something I might be misunderstanding about how to use the Strapi JS library within Next.js Server Components.

Is it expected to work correctly in this environment?

Or could this behavior point to a potential incompatibility or bug within the library itself when used in Server Components?

Any guidance on proper usage or confirmation regarding expected compatibility would be incredibly helpful. Thank you!

Version

1.0.0

Operating System

MacOS

Runtime Environment

Node.js

Logs

Media

this is what the missing header requests like

Image

and this is the requests sent from client components or typescript script

Image

Confirmation Checklist

  • I have checked the existing issues
  • I agree to follow this project's Code of Conduct
  • I would like to work on this issue

Metadata

Metadata

Assignees

Labels

issue: bugIssue reporting a bugstatus: confirmedThe issue has been confirmed or reproduced manually by a team member

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions