diff --git a/common/net/bufconn.go b/common/net/bufconn.go
index 37c8ba25..b7e98e04 100644
--- a/common/net/bufconn.go
+++ b/common/net/bufconn.go
@@ -84,9 +84,9 @@ func (c *BufferedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.C
 		length := c.r.Buffered()
 		b, _ := c.r.Peek(length)
 		_, _ = c.r.Discard(length)
-		c.r = nil // drop bufio.Reader to let gc can clean up its internal buf
 		return buf.As(b)
 	}
+	c.r = nil // drop bufio.Reader to let gc can clean up its internal buf
 	return nil
 }
 
diff --git a/common/net/bufconn_unsafe.go b/common/net/bufconn_unsafe.go
new file mode 100644
index 00000000..349321df
--- /dev/null
+++ b/common/net/bufconn_unsafe.go
@@ -0,0 +1,34 @@
+package net
+
+import (
+	"io"
+	"unsafe"
+)
+
+// bufioReader copy from stdlib bufio/bufio.go
+// This structure has remained unchanged from go1.5 to go1.21.
+type bufioReader struct {
+	buf          []byte
+	rd           io.Reader // reader provided by the client
+	r, w         int       // buf read and write positions
+	err          error
+	lastByte     int // last byte read for UnreadByte; -1 means invalid
+	lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid
+}
+
+func (c *BufferedConn) AppendData(buf []byte) (ok bool) {
+	b := (*bufioReader)(unsafe.Pointer(c.r))
+	pos := len(b.buf) - b.w - len(buf)
+	if pos >= -b.r { // len(b.buf)-(b.w - b.r) >= len(buf)
+		if pos < 0 { // len(b.buf)-b.w < len(buf)
+			// Slide existing data to beginning.
+			copy(b.buf, b.buf[b.r:b.w])
+			b.w -= b.r
+			b.r = 0
+		}
+
+		b.w += copy(b.buf[b.w:], buf)
+		return true
+	}
+	return false
+}
diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go
index b30bb8aa..8e675bb0 100644
--- a/transport/vmess/websocket.go
+++ b/transport/vmess/websocket.go
@@ -554,7 +554,14 @@ func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Co
 	}
 
 	if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 {
-		conn = N.NewCachedConn(conn, edBuf)
+		appendOk := false
+		if bufConn, ok := conn.(*N.BufferedConn); ok {
+			appendOk = bufConn.AppendData(edBuf)
+		}
+		if !appendOk {
+			conn = N.NewCachedConn(conn, edBuf)
+		}
+
 	}
 
 	return conn, nil