Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
- [Advanced Settings](advanced_settings) - An example of how to use the advanced connection settings of the AMQP 1.0 client.
- [Broadcast](broadcast) - An example of how to use fanout to broadcast messages to multiple auto-deleted queues.
- [RPC Echo](rpc_echo_server) - An example of how to implement RPC with the AMQP 1.0 client.
- [SQL stream Filtering](sql_stream_filter) - An example of how to use SQL stream filtering with RabbitMQ Streams.
- [SQL stream Filtering](sql_stream_filter) - An example of how to use SQL stream filtering with RabbitMQ Streams.
- [Web Sockets](web_sockets) - An example of how to use Web Sockets with the AMQP 1.0 client.
16 changes: 16 additions & 0 deletions docs/examples/web_sockets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
AMQP 1.0 over WebSocket Example
===============================================================

This example demonstrates how to use AMQP 1.0 over WebSocket. </br>
## RabbitMQ Tanzu
You need [Tanzu RabbitMQ 4.0](https://www.vmware.com/products/app-platform/tanzu-rabbitmq) or later with the AMQP 1.0 and `rabbitmq_web_amqp` plugins enabled.

For more info read the blog post: [AMQP 1.0 over WebSocket](https://www.rabbitmq.com/blog/2025/04/16/amqp-websocket)

To run the example you need to have:
- Tanzu RabbitMQ 4.0 or later with the AMQP 1.0 and `rabbitmq_web_amqp` plugins enabled.
- A vhost called `ws` configured for WebSocket connections.
- A user `rabbit` pwd `rabbit` with access to the `ws` vhost.
Comment on lines +12 to +13
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation mentions a vhost called 'ws' is required (line 12), but the example code uses the default vhost (no vhost specified in the connection string on line 17 of web_sockets.go). This inconsistency between documentation and code will confuse users. Either update the connection string to include the 'ws' vhost or correct the documentation to match the example.

Suggested change
- A vhost called `ws` configured for WebSocket connections.
- A user `rabbit` pwd `rabbit` with access to the `ws` vhost.
- A vhost (for example the default `/`) configured for WebSocket connections.
- A user `rabbit` pwd `rabbit` with access to that vhost.

Copilot uses AI. Check for mistakes.

## Web Sockify
Comment thread
Gsantomaggio marked this conversation as resolved.
It is possible to run the example with [websockify](https://github.com/novnc/websockify)
91 changes: 91 additions & 0 deletions docs/examples/web_sockets/web_sockets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// RabbitMQ AMQP 1.0 Go Client: https://github.com/rabbitmq/rabbitmq-amqp-go-client
// RabbitMQ AMQP 1.0 documentation: https://www.rabbitmq.com/docs/amqp
// The example is demonstrating how to connect to RabbitMQ using AMQP 1.0 over WebSocket protocol with SASLTypePlain,
// declare a queue, publish a message to it, and then consume that message.
// AMQP 1.0 over WebSocket documentation: https://www.rabbitmq.com/blog/2025/04/16/amqp-websocket
// example path: https://github.com/rabbitmq/rabbitmq-amqp-go-client/tree/main/docs/examples/web_sockets/web_sockets.go

package main

import (
"context"

"github.com/Azure/go-amqp"
rmq "github.com/rabbitmq/rabbitmq-amqp-go-client/pkg/rabbitmqamqp"
)

func main() {
const amqpConnectionString = "ws://127.0.0.1:15678/ws"
rmq.Info("[Example]", "Starting web socket connection to", amqpConnectionString)
// for anonymous connection use:
// env := rmq.NewEnvironment(amqpConnectionString, &rmq.AmqpConnOptions{
// SASLType: amqp.SASLTypeAnonymous(),
// })
env := rmq.NewEnvironment(amqpConnectionString, &rmq.AmqpConnOptions{
SASLType: amqp.SASLTypePlain("rabbit", "rabbit"),
})
conn, err := env.NewConnection(context.Background())
if err != nil {
panic(err)
}
_, err = conn.Management().DeclareQueue(context.TODO(), &rmq.QuorumQueueSpecification{
Name: "test-ws-queue",
})
if err != nil {
panic(err)
}
// declare new producer
producer, err := conn.NewPublisher(context.TODO(), &rmq.QueueAddress{
Queue: "test-ws-queue",
}, nil)
if err != nil {
panic(err)
}
msg := rmq.NewMessage([]byte("Hello over WebSockets"))

publishResult, err := producer.Publish(context.Background(), msg)
if err != nil {
panic(err)
}
switch publishResult.Outcome.(type) {
case *rmq.StateAccepted:
rmq.Info("[Publisher]", "Message accepted", publishResult.Message.Data[0])
default:
rmq.Warn("[Publisher]", "Message not accepted", publishResult.Message.Data[0])
}

// declare new consumer
consumer, err := conn.NewConsumer(context.TODO(), "test-ws-queue", nil)
if err != nil {
panic(err)
}
deliveryContext, err := consumer.Receive(context.Background())
if err != nil {
panic(err)
}
rmq.Info("[Consumer]", "Message received", string(deliveryContext.Message().GetData()))
err = deliveryContext.Accept(context.Background())
if err != nil {
panic(err)
}
// clean up
err = consumer.Close(context.TODO())
if err != nil {
panic(err)
}
err = producer.Close(context.TODO())
if err != nil {
panic(err)
}

err = conn.Management().DeleteQueue(context.Background(), "test-ws-queue")
if err != nil {
panic(err)
}

err = conn.Close(context.TODO())
if err != nil {
panic(err)
}

}
6 changes: 5 additions & 1 deletion pkg/rabbitmqamqp/amqp_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,14 +754,18 @@ func sanitizeWebSocketURL(rawURL string) (string, http.Header, error) {

// Prepare Headers for Auth
headers := http.Header{}
// add sec-websocket-protocol amqp
// mandatory for AMQP over WebSocket
// https://www.rfc-editor.org/rfc/rfc6455.html
headers.Add("Sec-WebSocket-Protocol", "amqp")

if u.User != nil {
username := u.User.Username()
password, _ := u.User.Password()

// Construct Basic Auth Header manually
auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
headers.Add("Authorization", "Basic "+auth)

u.User = nil
}

Expand Down