•  


WebSocket proxy fails if HMR is running on same port · Issue #6994 · parcel-bundler/parcel · GitHub
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebSocket proxy fails if HMR is running on same port #6994

Open
bminer opened this issue Sep 28, 2021 · 10 comments · May be fixed by #9432
Open

WebSocket proxy fails if HMR is running on same port #6994

bminer opened this issue Sep 28, 2021 · 10 comments · May be fixed by #9432
Labels

Comments

@bminer
Copy link

?? bug report

When running parcel serve where the --port is the same as the --hmr-port (the default behavior AFAIK), the WebSocket proxy (i.e. .proxyrc ) no longer functions properly.

?? Configuration

$ cat .proxyrc.json
{
	
"/ws"
: {
		
"target"
: 
"
http://localhost:1235/
"
,
		
"ws"
: 
true

	}
}

Running this command exhibits the bug:

parcel index.html

?? Expected Behavior

WebSocket proxy should work. When the browser connects to ws://localhost:1234/ws , it should be proxied to localhost:1235/ws using http-proxy-middleware

?? Current Behavior

When the browser establishes the WebSocket connection to ws://localhost:1234/ws , parcel indicates that the web browser immediately disconnects:

$ parcel --port 1234 --hmr-port 1234 index.html

Server running at http://localhost:1234
? Built in 1.76s
console: [HPM] Upgrading to WebSocket
console: [HPM] Client disconnected

On the WebSocket server running in Go on port 1235, I get an error that seems to indicate that the socket is closed:

failed to get reader: failed to read frame header: EOF

On the browser (Firefox), I get a message like this:

The connection to ws://localhost:1234/ws was interrupted while the page was loading.

which occurs on the line where I create the new WebSocket(...) .

?? Possible Solution

Everything runs fine without parcel . If I parcel build and bypass the parcel server and HMR server, it works.

Running Parcel with a different HMR port also seems to work (note that HMR port is set to 1236 ):

parcel --port 1234 --hmr-port 1236 index.html
$ parcel --port 1234 --hmr-port 1236 index.html

Server running at http://localhost:1234
? Built in 392ms
console: [HPM] Upgrading to WebSocket

... and in this case, it all works splendidly.

This seems to indicate that parcel serve does not properly handle WebSocket proxying with http-proxy-middleware when the HMR server is running on the same port as the normal parcel HTTP server.

?? Context

I'm just trying to run parcel serve [entry_point] and have it work (ideally without a separate HMR port).

?? Code Sample

I can provide a sample upon request, but it will take time.

?? Your Environment

Software Version(s)
Parcel 2.0.0-rc.0
Node v14.17.6
npm/Yarn npm 6.14.15
Operating System Linux Mint 20.2
Browser Firefox 92.0.1
Go 1.16.6
Go WebSocket lib nhooyr.io/websocket v1.8.7
@eirikb
Copy link

Thank you. Had the exact same issue, your solution worked perfectly.

@mistakenot
Copy link

+1 here also. I'm on parcel ^2.0.1 and socket.io-client ^4.3.2 , changing the hmr socket worked for me.

@nunof07
Copy link

Thank you. Your solution worked for me.

@dispalt
Copy link

Thank you so much! I was getting something like below (in case others run into this) on the server side (Scala/Java).

io.netty.handler.codec.http.websocketx.CorruptedWebSocketFrameException: bytes are not UTF-8

@github-actions github-actions bot added the Stale Inactive issues label Oct 26, 2022
@bminer
Copy link
Author

AFAIK, this is still an issue. Either a documentation change should be made to inform users of this, or the bug should be fixed.

@github-actions github-actions bot removed the Stale Inactive issues label Nov 7, 2022
@github-actions github-actions bot added the Stale Inactive issues label May 7, 2023
@xiemeilong
Copy link

This issue is still exist in the latest version.

@github-actions github-actions bot removed the Stale Inactive issues label May 7, 2023
@mischnic
Copy link
Member

This is the relevant code for the case of --port === --hmr-port .

let hmrServerOptions = {
port : serveOptions . port ,
host : hmrOptions . host ,
devServer ,
addMiddleware : handler => {
server ?. middleware . push ( handler ) ;
} ,
logger ,
} ;
hmrServer = new HMRServer ( hmrServerOptions ) ;

this . wss = new WebSocket . Server ( { server } ) ;

The HTTP server creation including proxyrc is here (the server here becomes devServer in HMRServer above):

const app = connect ( ) ;
app . use ( ( req , res , next ) => {
setHeaders ( res ) ;
next ( ) ;
} ) ;
await this . applyProxyTable ( app ) ;
app . use ( finalHandler ) ;
let { server , stop } = await createHTTPServer ( {
cacheDir : this . options . cacheDir ,
https : this . options . https ,
inputFS : this . options . inputFS ,
listener : app ,
outputFS : this . options . outputFS ,
host : this . options . host ,
} ) ;
this . stopServer = stop ;
server . listen ( this . options . port , this . options . host ) ;
return new Promise ( ( resolve , reject ) => {
server . once ( 'error' , err => {
this . options . logger . error (
( {
message : serverErrors ( err , this . options . port ) ,
} : Diagnostic ) ,
) ;
reject ( err ) ;
} ) ;
server . once ( 'listening' , ( ) => {
resolve ( server ) ;
} ) ;
} ) ;

@bminer
Copy link
Author

I think the issue is that the HMR server uses ws to create a new WebSocket server with the server option set:

this . wss = new WebSocket . Server ( { server } ) ;

This basically ensures that this.wss now handles all WebSocket requests for this.options.devServer ; thus, only HMR WebSocket requests work and WebSocket proxy requests using http-middleware-proxy are essentially closed preemptively by the HMR WebSocket upgrade handler. Here's the relevant code from the ws library:
https://github.com/websockets/ws/blob/06728e444d8f54aa5602b51360f4f98794cb1754/lib/websocket-server.js#L260-L263

The solution here is to tell the HMR WebSocket.Server to run in noServer mode and only handle upgrade events when it's for the HMR. See ws docs here . So line 89 above would change to:

this
.
wss
 =
 new
 WebSocket
.
Server
(
{
noServer
: 
true
}
)
;

and then the server's upgrade event would need to be handled manually as shown in this ws usage example :

server
.
on
(
'upgrade'
,
 function
 upgrade
(
req
,
 socket
,
 head
)
 {

  let
 {
pathname
}
 =
 url
.
parse
(
req
.
originalUrl
 ||
 req
.
url
)
;

  if
 (
pathname
 !=
 null
 &&
 pathname
.
startsWith
(
HMR_ENDPOINT
)
)
 {

    this
.
wss
.
handleUpgrade
(
req
,
 socket
,
 head
,
 function
 done
(
ws
)
 {

      this
.
wss
.
emit
(
'connection'
,
 ws
,
 req
)
;

    }
)
;

  }

  // else, we simply do nothing and hope the request got proxied

}
)
;

@bminer
Copy link
Author

Anyway, hope this is an easy fix. If you want, I can try my hand at a PR for this.

@bminer
Copy link
Author

PR is still open

@github-actions github-actions bot removed the Stale Inactive issues label May 27, 2024
Sign up for free to join this conversation on GitHub . Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants
- "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
- "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
- 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
- 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
 한국   대만   중국   일본