简体   繁体   中英

Error: This is caused by either a bug in Node.js or incorrect usage of Node.js internals

I was creating authentication mechanism for my service. And at some moment I had problem with cookies. More you can find here , so I solved this.

The problem was that I was trying to send cookie through 2 requests. My Next.js front-end sends request to its internal API, and only then, internal API sends this request to back-end.

The solution of this problem was very easy, what I had to do - is to set cookie on back-end and return it in headers. Here is how flow looks, like.

This is how it looks like, endpoint in Next.js front-end. Except of data in response, it receives header, where cookie is set (response from back-end) and send it in header of response, that will be send on front-end, where cookie will be set:

import { NextApiRequest, NextApiResponse } from "next";
import { AxiosError } from "axios";
import { api } from "../../../api";

export default async (
  req: NextApiRequest,
  res: NextApiResponse
) => {
  try {
    const { data, headers } = await api.post('/user/sign-in', req.body)

    if (headers["set-cookie"]) {
      res.setHeader("Set-Cookie", headers["set-cookie"]);
    }

    return res.json(data)
  } catch (error) {
    return res
      .status((error as AxiosError).response?.status as number)
      .json((error as AxiosError).response?.data);
  }
}

And endpoint on back-end:

import { Response as Res } from 'express';
import * as dayjs from 'dayjs';
...
async signIn(@Body() signInUserDto: SignInUserDto, @Response() res: Res) {
  const { _at, _rt } = await this.userService.signIn(signInUserDto);

  res.cookie('_rt', _rt, {
    httpOnly: true,
    expires: dayjs().add(7, 'days').toDate()
  });

  return res.send(_at);
}

And here is the problem, because of this Response class of express I keep getting this warning:

Error: This is caused by either a bug in Node.js or incorrect usage of Node.js internals.
Please open an issue with this stack trace at https://github.com/nodejs/node/issues

    at new NodeError (node:internal/errors:371:5)
    at assert (node:internal/assert:14:11)
    at ServerResponse.detachSocket (node:_http_server:249:3)
    at resOnFinish (node:_http_server:819:7)
    at ServerResponse.emit (node:events:390:28)
    at onFinish (node:_http_outgoing:830:10)
    at callback (node:internal/streams/writable:552:21)
    at afterWrite (node:internal/streams/writable:497:5)
    at afterWriteTick (node:internal/streams/writable:484:10)
    at processTicksAndRejections (node:internal/process/task_queues:82:21)

It is definitely because of how this signIn function looks like, because I was trying to return just like this - return this.userService.signIn(signInUserDto) - and it worked, but I can't cookie in this case.

So, my question is - what is this error? Can I just ignore it? If not, then how can I fix it?

Thanks in advance!

TL;DR

Finally, I was able to fix this error, first of all, as I said, my goes through 2 API's, from back-end to front-end API, and only then, this front-end API sends this request to actual front-end.

So, what I did, is just returned 2 tokens - refresh and access - as body.

@ApiOperation({ summary: 'Resource for sign in user.' })
@ApiResponse({ status: 200, type: TokensDto })
@Post('/sign-in')
async signIn(@Body() signInUserDto: SignInUserDto) {
  return this.userService.signIn(signInUserDto);
}

Then, on front-end, I installed cookie and @types/cookie and in this front-end endpoint, in headers, I just serialized this refresh token from body payload, and removed from it.

import { NextApiRequest, NextApiResponse } from "next";
import { AxiosError } from "axios";
import { api } from "../../../api";
import { serialize } from 'cookie';

export default async (
  req: NextApiRequest,
  res: NextApiResponse
) => {
  try {
    const { data } = await api.post('/user/sign-in', req.body)

    res.setHeader('Set-Cookie', serialize(
      '_rt',
      data._rt,
      { path: '/', httpOnly: true })
    );
    delete data._rt

    return res.json(data)
  } catch (error) {
    return res
      .status((error as AxiosError).response?.status as number)
      .json((error as AxiosError).response?.data);
  }
}

And it works perfectly fine, I don't have this Node.js error any more because of response with Express response class, and I'm able to set cookie.

EDIT

I have improved this code in even better way by using fastify and in the whole pipeline cookie is set in header. First of all, on back-end install @fastify/cookie and @nestjs/platform-fastify . Then, add this in file, where you start you Nest.js app:

import {
  FastifyAdapter,
  NestFastifyApplication
} from '@nestjs/platform-fastify';
import { fastifyCookie } from '@fastify/cookie';

async function bootstrap() {
  const PORT = process.env.PORT || 3002;
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter()
  );

  await app.register(fastifyCookie, {
    secret: 'my-secret'
  });

This will allow you to use FastifyReply from fastify , this will eliminate this Node.js error as response class:

import { FastifyReply } from 'fastify';

@ApiTags('User')
@Controller('user')
export class UserController {
  constructor(private userService: UserService) {}

  @Post('/sign-in')
  async signIn(
    @Body() signInUserDto: SignInUserDto,
    @Res({ passthrough: true }) res: FastifyReply
  ) {
    const { _at, _rt } = await this.userService.signIn(signInUserDto);

    res.setCookie('_rt', _rt);

    return res.send(_at);
  }
...

And the last step, on front-end endpoint, using cookie , parse this cookie and send it to front.

const { data, headers } = await api.post('/user/sign-in', req.body)

if (headers["set-cookie"]) {
  const refreshToken = headers["set-cookie"][0].split('=')[1];
  res.setHeader('Set-Cookie', serialize(
    '_rt', refreshToken, { path: '/', httpOnly: true })
  );
}

return res.json(data)

And this is the best way, that I've found, because it allows you to send cookie in header though all pipeline, not in body and then delete it, and this solution eliminates this strange Node.js error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM