
제가 개발 중인 모바일 앱에서는 WebSocket을 사용하여 다양한 정보를 구독/게시합니다. 대부분의 경우 앱 측 웹소켓은 단순히 리스너입니다. 그러나 메시지를 게시하는 경우도 있습니다.
서버 측 Nginx 위에서 작동하는 [NChan][1] 조합을 사용하여 이 문제를 처리하고 있습니다. NChan의 정말 멋진 기능 중 하나는 웹소켓을 "다중화"하는 기능입니다. 즉, 여러 채널에서 게시/구독 기능을 사용할 수 있습니다. 모바일 앱을 만들 때 이는 깔끔함과 배터리 친화성을 향상시키는 데 큰 도움이 됩니다.
pubsub
[NChan 문서][2]에 설명된 대로 다중화 채널을 설정했습니다.
location ~ /pubsub/(\w+)/(\w+)/(\w+)/(\w+)/(\w+)$
{
nchan_pubsub;
nchan_channel_id "$1" "$2" "$3" "$4" "$5" "control";
nchan_publisher_upstream_request /alter;
}
위의 세 번째 줄은 chan_publisher_upstream...
들어오는 pub
요청을 다른 서버로 전달합니다.
location = /alter
{
proxy_pass https://example.com;
proxy_set_header X-Publisher-Type $nchan_publisher_type;
proxy_set_header X-Prev-Message-Id $nchan_prev_message_id;
proxy_set_header X-Channel-Id $nchan_channel_id;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
index.php
다른 서버에서는 서버 루트 폴더 읽기에서 PHP를 실행하도록 Nginx를 설정했습니다.
<?php
trigger_error(json_encode(getallheaders()));//a test to see that the proxy pass is actually
happening
header("HTTP/1.1 304 Not Modified");
//if successful should cause the incoming request to be published without changes
//header("HTTP/1.1 204 No Content");
//when enable will suppress the incoming request (optionally after doing some server-side
//stuff with the incoming request data
//header("HTTP/1.1 200 OK");
//echo 'New Content!';
//when enabled should replace the incoming requestt content with the new one
?>
내가 알 수 있는 한, 나는 NChan 지침을 꽤 부지런히 따랐습니다. 그러나 이 구성을 사용하여 현재 정의된 채널에 게시하려고 하면 pubsub
클라이언트 연결이 예기치 않게 종료됩니다. 이 테스트를 수행하기 위해 몇 가지 간단한 JavaScript를 사용하고 있습니다.
var socket;
function connectPubSub()
{
socket = new WebSocket("wss://app.server.url/pubsub/personal/cause/beacon/grid/chat");
socket.onopen = whenOpen;
socket.onmessage = whenMessage;
socket.onclose = whenClose;
socket.onerror = whenError;
}
function whenOpen(e){console.log("[open] Connection established");}
function whenMessage(event){console.log(`[message]:${event.data}`);}
function whenClose(event)
{
if (event.wasClean)
alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
else console.log('[close] Connection died');
}
function whenError(error){console.log(`[error] ${error.message}`);}
function sendMessage(msg){socket.send(msg);}
이 시점에서 다음을 발행하려고 할 때
connectPubSub();
sendMessage('Hello world!');
아래에 표시된 출력을 얻습니다.
[open] Connection Established
Websocket connection to app.server.url failed:Close received after close
오류 이벤트는 아래와 같습니다.
bubbles: false
cancelBubble: false
cancelable: false
composed: false
currentTarget: WebSocket {url: "wss://app.server.url/pubsub/personal/cause/beacon/grid/chat",
readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}
defaultPrevented: false
eventPhase: 0
isTrusted: true
path: []
returnValue: true
srcElement: WebSocket {url: "wss://app.server.url/pubsub/personal/cause/beacon/grid/chat",
readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}
target: WebSocket {url: "wss://app.server.url/pubsub/personal/cause/beacon/grid/chat",
readyState: 3, bufferedAmount: 0, onopen: ƒ, onerror: ƒ, …}
timeStamp: 83208.4250000189
이것은 나를 당황하게 만들었습니다. 나는 단순히 NChan 문서를 따르고 다중 pubsub
채널에 메시지를 게시한 다음 무엇을 할지 결정하기 전에 프록시 서버에서 메시지 내용(JSON)을 검사 할 수 있을 것이라고 생각했습니다.
- 메시지 통과(HTTP 304 발행)
- 서버 측 조치를 취한 후 메시지를 억제합니다(HTTP 204 발행).
- 메시지를 수정하여 전송합니다(HTTP 200 발행).
Nginx 구성 지시문에 대한 나의 대략적인 지식으로 인해 아마도 나를 실망시킬 것입니다. 내가 도대체 뭘 잘못하고있는 겁니까?
나는 이제 여기서 무슨 일이 일어나고 있는지 확인할 수 있게 되었습니다. 여기서 문제의 근본 원인은 다음과 같습니다.
Proxy_pass https://example.com;
지령. 내가 그것을로 바꾸면
proxy_pass https://example.com/index.php;
상황이 예상대로 작동합니다. 그러나 왜 이런 일이 일어날 수 있는지는 아직 명확하지 않습니다. 내 Nginx 기본 구성 파일의 맨 위에는 다음 줄이 있습니다.
server
{
root /path/to/root;
index index.php;
server_name example.com;
위에서 세 번째 줄을 생각했는데,index index.php
Nginx에게 모든 폴더/하위 폴더 위치에서 index.php를 실행하도록 지시하는 데 필요한 전부라고 생각했습니다. 분명히 그렇지 않습니까? [1]:https://nchan.io
[2]:https://nchan.io/#getting-started