最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - WebSocket notifications not working with deployed Render URL but working locally - Stack Overflow

programmeradmin2浏览0评论

I am experiencing issues with WebSocket in my code. When using the deployed URL from Render (), I do not receive notifications on the frontend. However, when using http://localhost:5000, the notifications work as expected on the frontend.

import {
  addNotification,
  clearNotifications,
} from '@/features/notification/notificationSlice';
import { FC, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import socketIo from 'socket.io-client';

interface SocketComponentProps {
  children: React.ReactNode;
}

const SocketComponent: FC<SocketComponentProps> = ({ children }) => {
  const dispatch = useDispatch();

  const { userInfo } = useSelector((state: any) => state.user);
  const currentUserId = userInfo?.user?.id;
  const messages = useSelector((state: any) => state.chat.conversations);

  useEffect(() => {
    const socket = socketIo('', {
      transports: ['websocket'],
    });

    socket.on('connect', () => {
      console.log('Connected to WebSocket server:', socket.id);
    });

    socket.emit('joinNotifications', { userId: currentUserId });
    socket.on('notification', (notification) => {
      console.log('Notification received:', notification);
      dispatch(addNotification(notification));
    });

    return () => {
      socket.disconnect();
      socket.off('notification');
    };
  }, [messages, dispatch]);

  return <>{children}</>;
};

export default SocketComponent;

Here is the backend code

const { Server } = require('socket.io');

const app = express();enter code here

app.use('../public', express.static('public'));
app.use(bodyParser.json());
app.use(cors());

app.use(
  '/graphql',
  graphqlHTTP(async (req, res) => {
    const user = await authMiddleware(req, res);
    console.log({ user });
    return {
      schema,
      graphiql: true,
      context: {
        User,
        Property,
        currentUser: user,
        io,
      },
    };
  }),
);
const server = http.createServer(app);
const io = new Server(server, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST'],
  },
});

io.on('connection', (socket) => {
  socket.on('joinNotifications', ({ userId }) => {
    socket.join(userId);
  });
});

const port = process.env.PORT || 5000;

if (!module.parent) {
  server.listen(port, () => {
    logger.info(`server running on port ${port}`);
  });
}

module.exports = server;

here is the notification handler
const sendNotification = (io, userId, title, body, url = null) => {
  try {
    const notification = {
      title,
      body,
      timestamp: new Date(),
      read: false,
    };

    // Add the URL if provided
    if (url) {
      notification.url = url;
    }

    // Emit the notification to the user
    io.to(userId).emit('notification', notification);

    console.log({ notification });
  } catch (error) {
    console.error(`Error sending notification to user ${userId}:`, error);
  }
};

module.exports = sendNotification;

here is the graqhl mutation
requestApproval: {
      type: ApprovalType,
      args: {
        bookingId: { type: GraphQLNonNull(GraphQLID) },
        userId: { type: GraphQLNonNull(GraphQLID) },
        message: { type: GraphQLString },
      },
      resolve: async (parent, args, context) => {
        const { io } = context;

        //<--------- create an approval based on the booking id ---------->
        const approval = new Approval({
          booking: args.bookingId,
          user: args.userId,
          message: args.message,
        });

        const createdApproval = await approval.save();
        const booking = await Booking.findById(args.bookingId).populate('user property');
        //<---------- find the host who owns that property ---------->
        const host = await User.findById(booking.property.user);
        const hostEmail = host.email;

        const baseUrl = process.env.NODE_ENV === 'production' ? process.env.PROD_URL : process.env.DEV_URL;
        const manageShortletUrl = `${baseUrl}/manage-shortlets`;
        //<---------- email option for booking request ---------->
        const bookingDetails = {
          ...booking._doc,
          startDate: moment(booking.startDate).format('DD MMMM YYYY'),
          endDate: moment(booking.endDate).format('DD MMMM YYYY'),
        };
        const hostMail = {
          From: '[email protected]',
          To: hostEmail,
          Subject: `New Booking Request for ${booking.property.title}`,
          HtmlBody: BOOKING_REQUEST_TEMPLATE(host, bookingDetails, manageShortletUrl),
        };

        const notificationLink = `/review-booking/${booking.property._id.toString()}`;

        try {
          const result = await client.sendEmail(hostMail);

          sendNotification(
            io,
            host._id.toString(),
            'Booking Request',
            `You have a new booking request for your property ${booking.property.title}.`,
            notificationLink,
          );

          console.log('sent');
        } catch (error) {
          console.error('Error sending email to host:', error);
        }

        return createdApproval;
      },
    },

I am experiencing issues with WebSocket in my code. When using the deployed URL from Render (https://polis-backend-test.onrender), I do not receive notifications on the frontend. However, when using http://localhost:5000, the notifications work as expected on the frontend.

import {
  addNotification,
  clearNotifications,
} from '@/features/notification/notificationSlice';
import { FC, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import socketIo from 'socket.io-client';

interface SocketComponentProps {
  children: React.ReactNode;
}

const SocketComponent: FC<SocketComponentProps> = ({ children }) => {
  const dispatch = useDispatch();

  const { userInfo } = useSelector((state: any) => state.user);
  const currentUserId = userInfo?.user?.id;
  const messages = useSelector((state: any) => state.chat.conversations);

  useEffect(() => {
    const socket = socketIo('https://polis-backend-test.onrender', {
      transports: ['websocket'],
    });

    socket.on('connect', () => {
      console.log('Connected to WebSocket server:', socket.id);
    });

    socket.emit('joinNotifications', { userId: currentUserId });
    socket.on('notification', (notification) => {
      console.log('Notification received:', notification);
      dispatch(addNotification(notification));
    });

    return () => {
      socket.disconnect();
      socket.off('notification');
    };
  }, [messages, dispatch]);

  return <>{children}</>;
};

export default SocketComponent;

Here is the backend code

const { Server } = require('socket.io');

const app = express();enter code here

app.use('../public', express.static('public'));
app.use(bodyParser.json());
app.use(cors());

app.use(
  '/graphql',
  graphqlHTTP(async (req, res) => {
    const user = await authMiddleware(req, res);
    console.log({ user });
    return {
      schema,
      graphiql: true,
      context: {
        User,
        Property,
        currentUser: user,
        io,
      },
    };
  }),
);
const server = http.createServer(app);
const io = new Server(server, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST'],
  },
});

io.on('connection', (socket) => {
  socket.on('joinNotifications', ({ userId }) => {
    socket.join(userId);
  });
});

const port = process.env.PORT || 5000;

if (!module.parent) {
  server.listen(port, () => {
    logger.info(`server running on port ${port}`);
  });
}

module.exports = server;

here is the notification handler
const sendNotification = (io, userId, title, body, url = null) => {
  try {
    const notification = {
      title,
      body,
      timestamp: new Date(),
      read: false,
    };

    // Add the URL if provided
    if (url) {
      notification.url = url;
    }

    // Emit the notification to the user
    io.to(userId).emit('notification', notification);

    console.log({ notification });
  } catch (error) {
    console.error(`Error sending notification to user ${userId}:`, error);
  }
};

module.exports = sendNotification;

here is the graqhl mutation
requestApproval: {
      type: ApprovalType,
      args: {
        bookingId: { type: GraphQLNonNull(GraphQLID) },
        userId: { type: GraphQLNonNull(GraphQLID) },
        message: { type: GraphQLString },
      },
      resolve: async (parent, args, context) => {
        const { io } = context;

        //<--------- create an approval based on the booking id ---------->
        const approval = new Approval({
          booking: args.bookingId,
          user: args.userId,
          message: args.message,
        });

        const createdApproval = await approval.save();
        const booking = await Booking.findById(args.bookingId).populate('user property');
        //<---------- find the host who owns that property ---------->
        const host = await User.findById(booking.property.user);
        const hostEmail = host.email;

        const baseUrl = process.env.NODE_ENV === 'production' ? process.env.PROD_URL : process.env.DEV_URL;
        const manageShortletUrl = `${baseUrl}/manage-shortlets`;
        //<---------- email option for booking request ---------->
        const bookingDetails = {
          ...booking._doc,
          startDate: moment(booking.startDate).format('DD MMMM YYYY'),
          endDate: moment(booking.endDate).format('DD MMMM YYYY'),
        };
        const hostMail = {
          From: '[email protected]',
          To: hostEmail,
          Subject: `New Booking Request for ${booking.property.title}`,
          HtmlBody: BOOKING_REQUEST_TEMPLATE(host, bookingDetails, manageShortletUrl),
        };

        const notificationLink = `/review-booking/${booking.property._id.toString()}`;

        try {
          const result = await client.sendEmail(hostMail);

          sendNotification(
            io,
            host._id.toString(),
            'Booking Request',
            `You have a new booking request for your property ${booking.property.title}.`,
            notificationLink,
          );

          console.log('sent');
        } catch (error) {
          console.error('Error sending email to host:', error);
        }

        return createdApproval;
      },
    },

Share Improve this question asked Nov 18, 2024 at 16:40 Favour SamsonFavour Samson 212 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Most likely it is related to the hosting (or server) configuration. Some hosting (like Vercel) does not support sockets. https://vercel/guides/do-vercel-serverless-functions-support-websocket-connections

发布评论

评论列表(0)

  1. 暂无评论