- Mastering Node.js(Second Edition)
- Sandro Pasquali Kevin Faaborg
- 520字
- 2021-07-02 19:28:49
Proxying and tunneling
Sometimes, it is useful to provide a means for one server to function as a proxy, or broker, for other servers. This would allow one server to distribute a load to other servers, for example. Another use would be to provide access to a secured server to users who are unable to connect to that server directly. It is also common to have one server answering for more than one URL—using a proxy, that one server can forward requests to the right recipient.
Because Node has a consistent streams interface throughout its network interfaces, we can build a simple HTTP proxy in just a few lines of code. For example, the following program will set up an HTTP server on port 8080 which will respond to any request by fetching the front page of a website and piping that page back to the client:
const http = require('http');
const server = new http.Server();
server.on("request", (request, socket) => {
console.log(request.url);
http.request({
host: 'www.example.org',
method: 'GET',
path: "/",
port: 80
}, response => response.pipe(socket))
.end();
});
server.listen(8080, () => console.log('Proxy server listening on localhost:8080'));
Go ahead and start this server, and connect to it. Once this server receives the client socket, it is free to push content from any readable stream back to the client, and here, the result of GET of www.example.org is streamed. One can easily see how an external content server managing a caching layer for your application might become a proxy endpoint, for example.
Using similar ideas, we can create a tunneling service, using Node's native CONNECT support. Tunneling involves using a proxy server as an intermediary to communicate with a remote server on behalf of a client. Once our proxy server connects to a remote server, it is able to pass messages back and forth between that server and a client. This is advantageous when a direct connection between a client and a remote server is not possible, or not desired.
First, we'll set up a proxy server responding to HTTP CONNECT requests, then make a CONNECT request to that server. The proxy receives our client's Request object, the client's socket itself, and the head (the first packet) of the tunneling stream:
const http = require('http');
const net = require('net');
const url = require('url');
const proxy = new http.Server();
proxy.on('connect', (request, clientSocket, head) => {
let reqData = url.parse(`http://${request.url}`);
let remoteSocket = net.connect(reqData.port, reqData.hostname, () => {
clientSocket.write('HTTP/1.1 200 \r\n\r\n');
remoteSocket.write(head);
remoteSocket.pipe(clientSocket);
clientSocket.pipe(remoteSocket);
});
}).listen(8080);
let request = http.request({
port: 8080,
hostname: 'localhost',
method: 'CONNECT',
path: 'www.example.org:80'
});
request.end();
request.on('connect', (res, socket, head) => {
socket.setEncoding("utf8");
socket.write('GET / HTTP/1.1\r\nHost: www.example.org:80\r\nConnection: close\r\n\r\n');
socket.on('readable', () => {
console.log(socket.read());
});
socket.on('end', () => {
proxy.close();
});
});
Once we make a request to our local tunneling server running on port 8080 it will set up a remote socket connection to our destination and maintain this "bridge" between the remote socket and the (local) client socket. The remote connection of course only sees our tunneling server, and in this way clients can connect in a sense anonymously to remote services (which isn't always a shady practice!).
- 5G承載網網絡規劃與組網設計
- OpenLayers Cookbook
- Building RESTful Web Services with Spring 5(Second Edition)
- Learning Swift(Second Edition)
- Mastering Dart
- IPv6網絡切片:使能千行百業新體驗
- 互聯網安全的40個智慧洞見(2016)
- 物聯網基礎及應用
- 現場綜合化網絡運營與維護:運營商數字化轉型技術與實踐
- 從物聯到萬聯:Node.js與樹莓派萬維物聯網構建實戰
- Building Microservices with Spring
- 物聯網概論
- 5G與車聯網:基于移動通信的車聯網技術與智能網聯汽車
- 數字經濟時代的智慧城市與信息安全
- 揭秘:物聯網原理、實踐與解決方案 (清華開發者書庫)