在现代 Web 开发中,安全通信(HTTPS) 与 实时通信(WebSocket) 是非常重要的两项技术。HTTPS 解决数据安全问题,而 WebSocket 解决实时双向通信问题。在实际项目中,两者往往需要结合使用,例如在线聊天、实时通知、协同编辑等场景。
本文将结合 Go 语言与 Gin 框架,通过一个简单示例讲解 HTTPS 服务的搭建、WebSocket 的工作原理以及两者结合使用的方式。
一、HTTPS 的原理与作用
HTTPS 是在 HTTP 协议之上增加 TLS/SSL 加密层形成的一种安全通信协议。HTTPS 的主要目标是保证数据在网络传输过程中的安全性。
Go中HTTPS 的基本作用
HTTPS 主要提供三种安全能力:
1 数据加密
在普通 HTTP 通信中,请求和响应的数据是明文传输的。例如登录请求中的用户名和密码可以被中间节点轻易获取。而 HTTPS 在客户端和服务器之间建立加密通道,传输的数据会被加密处理,第三方无法直接读取。
例如:
普通 HTTP:
GET /login
username=admin&password=123
任何中间节点都可以看到。
HTTPS:
TLS加密后的数据
别人只能看到密文。
2 身份认证
HTTPS 通过数字证书来验证服务器的身份。服务器需要向客户端提供由证书机构签发的证书,浏览器会验证证书是否可信,从而确认服务器身份。
证书是否合法
证书是否属于这个域名
证书是否过期
3 数据完整性
HTTPS 使用消息摘要算法保证数据在传输过程中不会被篡改。如果数据被修改,客户端会检测到异常。
HTTPS的实现与流程
HTTPS建立流程
客户端请求
│
TLS握手
│
验证证书
│
协商加密算法
│
建立加密通道
│
HTTP请求
TLS握手流程
ClientHello
│
ServerHello
│
证书发送
│
客户端验证证书
│
生成会话密钥
│
双方使用对称加密通信
Go 标准库中Go net/http提供的 HTTPS 启动方法为
ListenAndServeTLS(
端口,
TLS证书,
私钥,
http handler
)
Go 实现 HTTPS 服务端
生成自签名证书(测试用):
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes
在git黑窗口中运行此命令,根据提示配置好后会在当前目录下生成如下两个文件

.crt即是证书,.key即是证书
Go
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
// 1. 初始化 Gin 路由(生产环境建议设为 Release 模式)
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
// 2. 定义测试接口(模拟你的其他业务操作)
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "pong (HTTPS)",
})
})
// 3. 启动 HTTPS 服务(核心:官方库的 ListenAndServeTLS)
// 参数说明:
// - ":443":HTTPS 默认端口(也可以用 8443 等自定义端口)
// - "server.crt":证书文件路径
// - "server.key":私钥文件路径
log.Fatal(http.ListenAndServeTLS(":8443", "D:/SPRING/server.crt", "D:/SPRING/server.key", r))
}
二、WebSocket 的使用与原理
WebSocket 的基本概念
传统 HTTP 协议采用 请求---响应模式,客户端发起请求后服务器才会返回数据。这种方式不适合实时通信场景,例如聊天系统、实时通知、股票行情推送等。
为了解决这个问题,引入了 WebSocket 协议。
WebSocket 的特点包括:
-
建立一次连接即可长期通信
-
支持服务器主动推送数据
-
支持双向通信
-
减少频繁 HTTP 请求带来的开销
因此 WebSocket 被广泛应用于实时系统。
WebSocket 建立流程
WebSocket 不是直接建立的 。它先走 HTTP升级协议。
1 客户端发送 HTTP 请求,并包含以下头信息:
Upgrade: websocket
Connection: Upgrade
2 服务器返回响应:
HTTP/1.1 101 Switching Protocols
3 连接从 HTTP 协议升级为 WebSocket 协议
HTTP连接
↓
升级
↓
WebSocket连接
一个 WebSocket 连接流程:
1 客户端发起连接
2 HTTP升级
3 建立WebSocket
4 双向通信
5 Ping/Pong心跳
6 关闭连接
Gin 中 WebSocket 的实现
在 Go 中常用的 WebSocket 库是gorilla/websocket。
升级 HTTP 请求为 WebSocket 连接的代码如下:
conn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
如果升级成功,就会获得一个 websocket.Conn 对象,这个对象代表客户端与服务器之间的长连接。
服务器可以通过该连接持续读取客户端消息:
msgType, msg, err := conn.ReadMessage()
一个简单的服务端示例
Go
package main
import (
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
// 1. 定义升级器:将 HTTP 请求升级为 WebSocket 连接
var upGrader = websocket.Upgrader{
// 允许跨域(测试用,生产环境可限制特定域名)
CheckOrigin: func(r *http.Request) bool {
return true
},
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
// 2. WebSocket 处理函数:处理客户端的连接和消息交互
func handleWebSocket(c *gin.Context) {
// 将 Gin 的 HTTP 请求升级为 WebSocket 连接
conn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Printf("升级 WebSocket 失败:%v", err)
return
}
// 延迟关闭连接(确保连接正常释放)
defer func(conn *websocket.Conn) {
err := conn.Close()
if err != nil {
log.Println("关闭失败")
}
}(conn)
log.Println("客户端已连接 WebSocket")
// 循环处理消息(持续监听客户端消息)
for {
// 读取客户端发送的消息(类型:文本/二进制/关闭等)
msgType, msg, err := conn.ReadMessage()
if err != nil {
log.Printf("读取消息失败/客户端断开连接:%v", err)
break
}
// 打印客户端消息
log.Printf("收到客户端消息:%s", string(msg))
// 给客户端回复消息(echo 回声)
replyMsg := "服务端已收到:" + string(msg) + " [" + time.Now().Format("15:04:05") + "]"
err = conn.WriteMessage(msgType, []byte(replyMsg))
if err != nil {
log.Printf("回复消息失败:%v", err)
break
}
}
}
func main() {
// 生产环境模式
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
// 3. 注册路由
// HTTP 接口(测试用)
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
})
// WebSocket 接口(核心)
r.GET("/ws", handleWebSocket)
r.StaticFile("/", "D:/Go_WorkSpace/Gin/index.html")
// 4. 启动服务(支持 HTTP/HTTPS,二选一即可)
// 方式1:启动 HTTP 服务(测试用,简单)
// log.Fatal(r.Run(":8080"))
// 方式2:启动 HTTPS 服务
certFile := "D:/SPRING/server.crt"
keyFile := "D:/SPRING/server.key"
log.Fatal(http.ListenAndServeTLS(":8443", certFile, keyFile, r))
}
写一个Html来做测试
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket 测试</title>
</head>
<body>
<input type="text" id="msgInput" placeholder="输入消息">
<button onclick="sendMsg()">发送</button>
<div id="msgBox"></div>
<script>
// 连接 WebSocket(根据你的服务类型选择)
// const ws = new WebSocket("ws://localhost:8080/ws"); // HTTP
const ws = new WebSocket("wss://localhost:8443/ws"); // HTTPS
// 连接成功回调
ws.onopen = function() {
addMsg("已连接到服务端");
};
// 接收服务端消息
ws.onmessage = function(event) {
addMsg("服务端回复:" + event.data);
};
// 连接关闭回调
ws.onclose = function() {
addMsg("与服务端断开连接");
};
// 发送消息
function sendMsg() {
const input = document.getElementById("msgInput");
const msg = input.value.trim();
if (msg) {
ws.send(msg);
addMsg("我发送:" + msg);
input.value = "";
}
}
// 显示消息到页面
function addMsg(text) {
const box = document.getElementById("msgBox");
box.innerHTML += "<p>" + text + "</p>";
}
</script>
</body>
</html>
浏览器
│
HTTPS请求
│
Gin服务器
│
HTTP接口
/ping
│
WebSocket接口
/ws
│
升级连接
│
WebSocket长连接