본문 바로가기

네트워크

Handshake failed due to invalid Upgrade header: null

문제상황

SSAFY 자율 프로젝트에서 채팅 기능을 구현하는데 잘 동작하던 기능이 HTTPS를 적용하고 나서는 콘솔에 아래와 같은 에러가 발생하면서 채팅방에서 소켓연결이 실패했었습니다. 

 

백엔드단에서도 로그를 확인해 보니 동일한 에러가 발생했습니다.

(개발할 때 에러메세지를 캡처하지 못해서 문제를 해결할 때 참고했던 블로그의 사진을 인용하였습니다.)

 

 

"Handshake failed due to invalid Upgrade header: null"

내 기존 location 들 , 아래를 추가

velog.io

해결방법

Websocket 프로토콜은 서버와 클라이언트 간의 메세지 교환을 위한 통신 프로토콜로 양방향 통신을 지원하며 실시간 네트워크를 구현하는데 주로 사용됩니다.

HTTP 프록시 및 중간 층을 지원하도록 설계되었으므로 HTTP 프로토콜과 호환이 된다. 호환을 달성하기 위해 웹소켓 핸드셰이크는 HTTP 업그레이드 헤더를 사용하여 HTTP 프로토콜에서 웹소켓 프로토콜로 변경한다.

 

위키백과를 보면 HTTP 프로토콜을 Websocket 프로토콜로 변경하기 위해 클라이언트에서 upgrade 헤더를 전달해야한다고 명시되어 있는데 아래 nginx 공식 문서를 보면 리버스 프록시 환경에서는 Upgrade는 hop-by-hop 헤더이기 때문에 클라이언트에서 프록시 서버로 전달되지 않는다고 설명하고 있습니다.

There is one subtlety however: since the “Upgrade” is a hop-by-hop header, it is not passed from a client to proxied server. With forward proxying, clients may use the CONNECT method to circumvent this issue. This does not work with reverse proxying however, since clients are not aware of any proxy servers, and special processing on a proxy server is required.
 

WebSocket proxying

WebSocket proxying To turn a connection between a client and server from HTTP/1.1 into WebSocket, the protocol switch mechanism available in HTTP/1.1 is used. There is one subtlety however: since the “Upgrade” is a hop-by-hop header, it is not passed f

nginx.org

동시에 해결방법으로 아래와 같이 nginx를 설정할 때 upgrade 헤더를 추가해주는 방법을 제시하고 있었습니다.

그래서 저희가 MSA 구조로 프로젝트를 개발했었기 때문에 채팅 서비스로 요청을 보낼때는 아래와 같이 upgrade 헤더를 추가해줌으로써 문제를 해결할 수 있었습니다.

 

upstream frontend {
    server localhost:3000;
}

upstream backend {
    server localhost:8000;
}

server {
    listen 80;
    server_name k8c101.p.ssafy.io;

    ...

    location /chatting-service {
        proxy_pass http://backend/chatting-service;
        proxy_set_header X-Forwarded-Proto $scheme;
        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 Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name k8c101.p.ssafy.io;

    ssl_certificate /etc/letsencrypt/live/k8c101.p.ssafy.io/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/k8c101.p.ssafy.io/privkey.pem;

    ...

    location /chatting-service {
        proxy_pass http://backend/chatting-service;
        proxy_set_header X-Forwarded-Proto $scheme;
        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 Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

'네트워크' 카테고리의 다른 글

OSI 7계층, TCP/IP 4계층  (0) 2023.05.24
[HTTP] HTTP, HTTPS, SSL Handshake  (0) 2022.11.28
[HTTP] TCP와 UDP의 특징 (TCP 3-way, 4-way handshake)  (0) 2022.11.27
[HTTP] 쿠키와 세션  (0) 2022.09.30
[HTTP] 웹 통신 흐름  (0) 2022.05.14