diff --git a/contrib/codecs/http/handler.go b/contrib/codecs/http/handler.go
index 6c2cd253a33b1c8937d366008cc02d1439530b14..f47bdf73e72c8afcca45369ae8bbb8006060e7b2 100644
--- a/contrib/codecs/http/handler.go
+++ b/contrib/codecs/http/handler.go
@@ -5,10 +5,12 @@ import (
 	"sync"
 
 	"gfx.cafe/open/jrpc/pkg/server"
+	"golang.org/x/net/http2"
+	"golang.org/x/net/http2/h2c"
 )
 
 func HttpHandler(s *server.Server) http.Handler {
-	return &Server{Server: s}
+	return h2c.NewHandler(&Server{Server: s}, &http2.Server{})
 }
 
 type Server struct {
diff --git a/contrib/codecs/rdwr/client.go b/contrib/codecs/rdwr/client.go
index 741872f8965ca022fb15cd247feae45a679eeda1..c9fa522657d4b26b056cb6bdb146a2b12f45b907 100644
--- a/contrib/codecs/rdwr/client.go
+++ b/contrib/codecs/rdwr/client.go
@@ -23,7 +23,9 @@ type Client struct {
 
 	m       codec.Middlewares
 	handler codec.Handler
-	mu      sync.RWMutex
+	writeCh chan struct{}
+
+	mu sync.RWMutex
 
 	handlerPeer codec.PeerInfo
 }
@@ -38,6 +40,7 @@ func NewClient(rd io.Reader, wr io.Writer) *Client {
 			RemoteAddr: "",
 		},
 		handler: codec.HandlerFunc(func(w codec.ResponseWriter, r *codec.Request) {}),
+		writeCh: make(chan struct{}, 1),
 	}
 	cl.ctx, cl.cn = context.WithCancel(context.Background())
 	go cl.listen()
@@ -209,17 +212,12 @@ func (c *Client) Close() error {
 }
 
 func (c *Client) writeContext(ctx context.Context, xs []byte) error {
-	errch := make(chan error)
-	go func() {
-		_, err := c.wr.Write(xs)
-		select {
-		case errch <- err:
-		case <-ctx.Done():
-		case <-c.ctx.Done():
-		}
-	}()
 	select {
-	case err := <-errch:
+	case c.writeCh <- struct{}{}:
+		defer func() {
+			<-c.writeCh
+		}()
+		_, err := c.wr.Write(xs)
 		return err
 	case <-c.ctx.Done():
 		return c.ctx.Err()
diff --git a/go.mod b/go.mod
index c912ba093165b9aaba37ae0303e4d8248d2800eb..83b1f32f4363c553c9324bc26598906724e6862f 100644
--- a/go.mod
+++ b/go.mod
@@ -13,8 +13,8 @@ require (
 	gfx.cafe/util/go/generic v0.0.0-20230721185457-c559e86c829c
 	github.com/go-faster/jx v1.1.0
 	github.com/goccy/go-json v0.10.2
-	github.com/rs/xid v1.5.0
 	github.com/stretchr/testify v1.8.4
+	golang.org/x/net v0.17.0
 	golang.org/x/sync v0.4.0
 	sigs.k8s.io/yaml v1.3.0
 )
@@ -28,7 +28,8 @@ require (
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/segmentio/asm v1.2.0 // indirect
 	golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect
-	golang.org/x/sys v0.12.0 // indirect
+	golang.org/x/sys v0.13.0 // indirect
+	golang.org/x/text v0.13.0 // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/go.sum b/go.sum
index ef1477ba7ccd35f66b491e65ce0f5795afde6040..d8f9eeda07441c8640114e1ee558daef2741e90a 100644
--- a/go.sum
+++ b/go.sum
@@ -35,18 +35,20 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
 github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
 golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
 golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=