websocket 如何修复“Firefox无法在wss://example.domain/subscription建立到服务器的连接”问题?

wvyml7n5  于 2023-04-21  发布在  其他
关注(0)|答案(1)|浏览(571)

下面是我如何设置app.js:

/**
 *  Importing Packages
 */
require("dotenv").config({ path: `./env/.env-${process.env.NODE_ENV}` });
const express                                 = require("express");
const logger                                  = require("morgan");
const moment                                  = require("moment");
const cors                                    = require("cors");
const path                                    = require("path");
const bodyParser                              = require('body-parser');
const app                                     = express();
const fs                                      = require("fs");
const { ApolloServer, gql }                   = require("apollo-server-express");
const { mergeGraphQLTypes, mergeResolvers }   = require("@graphql-tools/merge");
const { makeExecutableSchema }                = require("@graphql-tools/schema");
const { applyMiddleware }                     = require("graphql-middleware");
const { createServer }                        = require("http"); // newly added
const { 
  ApolloServerPluginDrainHttpServer, 
  ApolloServerPluginLandingPageLocalDefault } = require("apollo-server-core");
const { WebSocketServer }                     = require("ws");
const { useServer }                           = require("graphql-ws/lib/use/ws");
const graphqlUploadExpress                    = require("graphql-upload/graphqlUploadExpress.js");
const GraphQLUpload                           = require("graphql-upload/GraphQLUpload.js");

require("./database/db");
require("./helper/function");
const Stripe                                  = require("./stripe/stripeRoute");
const Cron                                    = require("./scheduleCron/scheduleCronRoute");
const generateFolder                          = Helper("generate-folder");

/* Get the Queries & Mutation type and merge them togather for the schema */
const Query                                   = mergeGraphQLTypes(require("./queries")(gql));

/* Get the resolvers array and merge them togather for the schema */
const Resolvers                               = mergeResolvers(require("./resolvers"));
Resolvers.Upload                              = GraphQLUpload;

/* Get all the middlewares.
   Note:- This we can return as array of middleware object
   The object pattern are mentioned in the middleware folder index.js file */
const Middlewares                             = require("./middlewares");

/* For the use of middleware we must create an executable schema and pass the
   query and resolvers we acquired before. */
const schema                                  = makeExecutableSchema({ typeDefs: Query, resolvers: Resolvers });

/* Apply middlewares to the schema. */
const schemaWithMiddleware                    = applyMiddleware(schema, Middlewares.verifyUser);

/* Create the main Apollo Server from the schema */
// Added for Websocket Subscriptions Starts //
const httpServer                              = createServer(app);
// Set up WebSocket server.
const wsServer = new WebSocketServer({
  //port: 8443,
  server: httpServer,
  path: "/",
});
const serverCleanup = useServer({schema}, wsServer);
// Added for Websocket Subscriptions Ends //

const server = new ApolloServer({
  schema: schemaWithMiddleware,
  context: ({ req, res }) => {
    return { req, res };
  },
  formatError: (err) => {
    // logger.info(err);
    return err;
  },
  uploads: false,
  plugins: [
    // Proper shutdown for the HTTP server.
    ApolloServerPluginDrainHttpServer({httpServer}),
    {
      async serverWillStart() {
        return {
          async renderLandingPage() {
            const html = `<!DOCTYPE html>
                          <html>
                            <head>
                            <title>Welcome To TestDrive</title>
                            </head>
                            <body>
                              <img src="https://testdrive.co/images/api-screen.jpg" style="display: block; margin-left: auto; margin-right: auto; width:auto;">
                            </body>
                          </html>`;
            return { html };
          },
          async drainServer() {
            await serverCleanup.dispose();
          },
        }
      }
    }
  ]
});

/* Setting up port */
const port = process.env.PORT || 8000;

/* Generating logs */
var accessLogStream = fs.createWriteStream(
  path.join(
    __dirname,
    `${generateFolder.generateLogFolder()}/access-${moment().format(
      "YYYY-MM-DD"
    )}.log`
  ),
  { flags: "a" }
);

// setting up the logger
app.use(logger("combined", { stream: accessLogStream }));
app.use(function (err, req, res, next) {
  logger.error(
    `${req.method} - ${err.message}  - ${req.originalUrl} - ${req.ip}`
  );
  next(err);
});

/* Setting up stripe payment */
app.use(
  express.json({
    // We need the raw body to verify webhook signatures.
    // Let's compute it only when hitting the Stripe webhook endpoint.
    verify: function (req, res, buf) {
      if (req.originalUrl.startsWith("/webhook")) {
        req.rawBody = buf.toString();
      }
    },
  })
);

/* Setting up graphql upload */
app.use(
  graphqlUploadExpress({
    maxFileSize: 30000000,
    maxFiles: 20,
  })
);

/* Cors Setup */
var corsOptions = {
  origin: process.env.CORS_ALLOW_URL,
  allowedHeaders: [
    "Content-Type",
    "Authorization",
    "Accept",
    "x-www-form-urlencoded",
    "x-access-token",
  ],
  credentials: true,
};
app.use(cors(corsOptions));
app.use(express.static("public"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(Stripe);
app.use(Cron);

/* Initiating the Apollo server */
server
  .start()
  .then((r) => {
    /**
     * The following line is require as we are using the apollo-server-express
     */
    server.applyMiddleware({ app, path: "/" });

    // Now that our HTTP server is fully set up, actually listen.
    httpServer.listen(port, () => {
      console.log(`🚀 Query endpoint ready at http://localhost:${port}${server.graphqlPath}`);
      console.log(`🚀 Subscription endpoint ready at ws://localhost:${port}${server.graphqlPath}`);
    });
  })
  .catch((err) => {
    console.log("Could not start the apollo server", err);
  });

这是我的nginx设置:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream sockettest.testdrive.co {
  server 100.242.100.242:5555; #  host and port of local running server instance
}

server {
    ssl on;
    listen 443 ssl http2;
    server_name apistg.testdrive.co;
    ssl_certificate /etc/testdrives/testcert.pem;
    ssl_certificate_key /etc/testdrives/testkey.pem;

    root /var/www/apistg.testdrive.co/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    location / {
        proxy_pass http://100.242.100.242:5555/;
        proxy_buffering off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
    }

    location /subscription { # websocket endpoint
      proxy_pass http://sockettest.testdrive.co/;

      # upstream url and host
      
      proxy_redirect     default;
      proxy_http_version 1.1;

      proxy_set_header   Connection        $connection_upgrade;
      proxy_set_header   Upgrade           $http_upgrade; 

      proxy_set_header   Host              $host;
      proxy_set_header   X-Real-IP         $remote_addr;
      proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Proto $scheme;

      client_max_body_size       10m;
      client_body_buffer_size    128k;

      proxy_connect_timeout      90;
      proxy_send_timeout         90;
      proxy_read_timeout         90;
  }

    location /graphql {
        proxy_pass http://100.242.100.242:5555/graphql;
        proxy_buffering off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
   }

    # Secure Headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "origin-when-cross-origin" always;
    add_header "X-XSS-Protection" "1; mode=block";
}

WebSocket在chrome,opera等中运行良好。只有在Firefox中,我得到这个错误:-

Firefox can’t establish a connection to the server at wss://testdrive.co/subscription.

不。Firefox中并不总是发生这种情况。5次中有2次,Firefox没有显示此错误。但5次中有3次,此问题正在发生。
我怎么解决这个问题?有人说可能是fixed通过nginx中的proxy_pass(在已接受答案的评论部分)但是我不能修复它。我发现的另一个work around是在Firefox中手动访问链接http://testdrive.co/subscription并接受证书警告。但是该项目是一个SAAS应用程序。我不能't要求所有用户打开链接并接受如下证书警告:

9cbw7uwe

9cbw7uwe1#

请检查下面的链接。https://www.nginx.com/blog/websocket-nginx/?amp=1
如果你有一个SaaS服务,你需要激活https,http不安全,浏览器不能正常工作。
你必须检查WS和WSS是否在浏览器外正常,如果连接正常,检查浏览器和证书。
希望能帮上忙

相关问题