Java通过代理连接带URL路径的MongoDB及连接超时问题排查
Let's break down why you're hitting that timeout and walk through the fixes step by step:
First, Fix Your Connection String
The immediate red flag in your error is the address server.com/mongo:80 — your MongoDB driver is treating server.com/mongo as a single hostname, which doesn't exist. That's almost certainly because you formatted your connection string incorrectly.
Wrong: mongodb://server.com/mongo:80/dbName
Right: mongodb://server.com:80/dbName
But this alone won't solve the problem, since your proxy expects the /mongo path prefix. Let's tackle that next.
Option 1: Adjust Your Reverse Proxy Configuration (Recommended)
If you have control over the proxy (like Nginx), the simplest fix is to set up a TCP forward instead of using a path-based HTTP proxy. MongoDB uses a binary protocol, which doesn't play nicely with HTTP path prefixes by default.
For Nginx, use the stream module instead of http to forward traffic directly from port 80 to your MongoDB instance:
stream { server { listen 80; proxy_pass localhost:27017; # Replace with your internal MongoDB address:port } }
With this setup, your corrected connection string (mongodb://server.com:80/dbName) will work immediately, no extra driver configuration needed.
Option 2: Customize the Java Driver to Handle the Path Prefix
If you can't modify the proxy (e.g., strict environment restrictions), you'll need to add custom logic to your driver to send the /mongo path before initiating the MongoDB binary protocol. This assumes your proxy accepts an HTTP request first, then switches to forwarding TCP traffic for MongoDB.
Step 1: Create a Custom Socket Stream Factory
This factory will establish the socket connection, send the required path prefix via HTTP, then hand off to the MongoDB driver:
import com.mongodb.connection.SocketStreamFactory; import com.mongodb.connection.SocketSettings; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class PathPrefixedStreamFactory extends SocketStreamFactory { private final String pathPrefix; public PathPrefixedStreamFactory(SocketSettings settings, String pathPrefix) { super(settings); this.pathPrefix = pathPrefix; } @Override protected Socket createSocket() throws IOException { Socket socket = super.createSocket(); // Send HTTP request with the path prefix (adjust based on your proxy's requirements) OutputStream out = socket.getOutputStream(); String httpRequest = String.format("GET %s HTTP/1.1\r\nHost: server.com\r\n\r\n", pathPrefix); out.write(httpRequest.getBytes()); out.flush(); // Optional: Read the proxy's HTTP response to confirm connection (adjust as needed) // InputStream in = socket.getInputStream(); // // Read response headers here to ensure proxy accepts the request return socket; } }
Step 2: Configure MongoClient with the Custom Factory
Use this factory when building your MongoClient to inject the path handling logic:
import com.mongodb.ConnectionString; import com.mongodb.MongoClientSettings; import com.mongodb.client.MongoClients; import com.mongodb.connection.SocketSettings; public class MongoProxyConnection { public static void main(String[] args) { SocketSettings socketSettings = SocketSettings.builder() .connectTimeout(30000) .build(); // Initialize our custom factory with the /mongo path PathPrefixedStreamFactory streamFactory = new PathPrefixedStreamFactory(socketSettings, "/mongo"); MongoClientSettings clientSettings = MongoClientSettings.builder() .applyConnectionString(new ConnectionString("mongodb://server.com:80/dbName")) .applyToSocketSettings(builder -> builder.applySettings(socketSettings)) .streamFactoryFactory((socketSettings1, sslSettings) -> streamFactory) .build(); // Test the connection try (var mongoClient = MongoClients.create(clientSettings)) { var db = mongoClient.getDatabase("dbName"); db.listCollectionNames().first(); // Trigger a connection System.out.println("Successfully connected to MongoDB via proxy!"); } catch (Exception e) { e.printStackTrace(); } } }
Important Notes for Option 2
- This relies on your proxy supporting the HTTP-to-TCP switch. If your proxy only handles HTTP requests, this won't work (MongoDB's binary protocol isn't compatible with HTTP).
- Double-check that your environment allows outbound connections to
server.com:80— even if no ports are open inbound, outbound traffic to port 80 is usually permitted.
内容的提问来源于stack exchange,提问作者Kévin Darty

