Golang成为我后端Web开发的新"Perl"
Golang成为我后端Web开发的新"Perl"
多年来(超过20年),我一直在运行Apache并配置了多个虚拟主机的各种Web服务器上开发和托管网站及Web应用。我一直使用Perl进行后端工作(如MySQL/安全等)。因此,我的某个应用/站点可能在/cgi目录下拥有100个或更多的Perl脚本,这些脚本通常通过ajax从客户端的JavaScript调用,以填充浏览器页面。
Perl已不再像过去那样有用,其支持和库也不再那么普遍,因此我清楚地意识到需要做出改变。我考察了其他脚本语言——如Python等——但在研究了几种之后,我意识到Go将是一个非常适合转换的语言。我花了一些时间学习它,并逐渐欣赏它的所有优点。
但是,当试图用它替代Perl时,很快就发现这并非简单的替换。为网站编写数十个Go应用程序显然不是正确的方法。我发现的大多数文章都在讨论如何使用Go编写服务器,该服务器运行在不同的端口上,通过mux和各种处理器来处理不同的ajax调用——并且不从Apache调用。我的站点/应用大量使用了js/css/scss和一些框架(如Bootstrap等)。
所以,我理解了这个思路——我需要一个Go应用(服务器/守护进程)来监听所有在不同端口(例如8080)上的调用,然后执行后端工作,再将结果返回给客户端。
这正是我难以理解如何进行下去的地方…… 如果我有很多由Apache管理的虚拟主机,我是否需要为我托管的每个站点/应用运行一个Go服务器应用(守护进程)……并且每个都监听不同的端口(8080、8081、8082……等)……
我花了大量时间寻找指导/答案……但没有找到任何关于这种情况的参考资料——我找到的每篇文章都在讨论Go服务器/守护进程。请问有人能为我指明正确的方向吗?
更多关于Golang成为我后端Web开发的新"Perl"的实战教程也可以访问 https://www.itying.com/category-94-b0.html
欢迎来到 GolangBridge 🚀 🎆
Upland: 如果我有很多由 Apache 管理的虚拟主机,我是否需要为托管的每个站点/应用运行一个 Go 服务器应用(守护进程)……并且每个都监听不同的端口(8080, 8081, 8082 … 等等)……
这个问题的答案取决于你的整体架构和程序。你提到的设计是“反向代理和服务”方法(Apache 充当反向代理,每个 站点/应用 都有自己专用的服务器,拥有一个端口号)。
我可以告诉你的是,Go 服务器既可以扮演 Apache 的角色(一个庞大的应用),也可以作为专用的“服务”服务器。因此,你不需要抛弃现有的 Apache 系统。关键在于,如果需求允许,Go 可以在没有 Apache/Nginx 的情况下运行。
我无法为你做决定,因为这是一个设计问题。也许结合你的需求和资源进行交叉核对,能带来一些启发。
Upland: 我花了大量时间搜索指导/答案……但没有找到任何关于这种情况的参考资料——我找到的每篇文章都在谈论 Go 服务器/守护进程。有人能给我指个正确的方向吗?
你正在寻找的是一个系统设计问题,而不是一个具体的 Go 编程语言查询。这些关键词对你接下来的搜索有帮助吗?
deployment go server strategy production
根据你的描述,你正在寻找一种将现有Apache+Perl架构迁移到Go的方案,同时保留Apache的虚拟主机管理能力。以下是几种可行的技术方案:
方案一:Go作为独立后端服务(推荐)
创建独立的Go服务处理业务逻辑,Apache通过反向代理转发请求:
// backend.go - 统一业务处理服务
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
// 按功能模块路由,替代原来的多个Perl脚本
r.HandleFunc("/api/user/{action}", handleUser).Methods("POST")
r.HandleFunc("/api/data/{action}", handleData).Methods("POST")
r.HandleFunc("/api/report/{action}", handleReport).Methods("POST")
// 启动服务在8080端口
log.Println("Go后端服务启动在 :8080")
log.Fatal(http.ListenAndServe(":8080", r))
}
func handleUser(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
action := vars["action"]
// 解析JSON请求
var req map[string]interface{}
json.NewDecoder(r.Body).Decode(&req)
// 根据action执行不同逻辑
switch action {
case "login":
// 登录逻辑
response := map[string]interface{}{
"status": "success",
"data": "用户登录成功",
}
json.NewEncoder(w).Encode(response)
case "profile":
// 获取用户资料
response := map[string]interface{}{
"status": "success",
"data": "用户资料",
}
json.NewEncoder(w).Encode(response)
}
}
Apache配置反向代理:
# Apache虚拟主机配置
<VirtualHost *:80>
ServerName example.com
# 静态文件仍由Apache处理
DocumentRoot /var/www/example.com
# 动态请求转发到Go服务
ProxyPass /api http://localhost:8080/api
ProxyPassReverse /api http://localhost:8080/api
# CGI目录重定向
RedirectMatch 301 ^/cgi/(.*)$ /api/$1
</VirtualHost>
方案二:每个虚拟主机独立Go服务
如果业务完全隔离,可为每个站点运行独立Go服务:
// site1.go - 站点1的后端服务
package main
import (
"net/http"
"log"
)
func main() {
mux := http.NewServeMux()
// 站点1的API端点
mux.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
// 处理站点1的业务逻辑
w.Write([]byte("Site1 API Response"))
})
log.Println("站点1服务启动在 :8081")
http.ListenAndServe(":8081", mux)
}
// site2.go - 站点2的后端服务
package main
import (
"net/http"
"log"
)
func main() {
mux := http.NewServeMux()
// 站点2的API端点
mux.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
// 处理站点2的业务逻辑
w.Write([]byte("Site2 API Response"))
})
log.Println("站点2服务启动在 :8082")
http.ListenAndServe(":8082", mux)
}
Apache配置:
# 站点1
<VirtualHost *:80>
ServerName site1.com
ProxyPass /api http://localhost:8081/api
ProxyPassReverse /api http://localhost:8081/api
</VirtualHost>
# 站点2
<VirtualHost *:80>
ServerName site2.com
ProxyPass /api http://localhost:8082/api
ProxyPassReverse /api http://localhost:8082/api
</VirtualHost>
方案三:Go处理特定路径模式
使用Apache的Location或FilesMatch将特定请求路由到Go:
// cgi_handler.go - 处理所有/cgi路径请求
package main
import (
"net/http"
"strings"
"log"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 提取原始Perl脚本名
path := r.URL.Path
// 模拟Perl CGI脚本路由
if strings.Contains(path, ".pl") {
scriptName := strings.TrimSuffix(path, ".pl")
scriptName = strings.TrimPrefix(scriptName, "/cgi/")
// 根据脚本名路由到对应处理函数
switch scriptName {
case "login":
handleLogin(w, r)
case "get_data":
handleGetData(w, r)
case "update_record":
handleUpdateRecord(w, r)
default:
http.NotFound(w, r)
}
}
})
log.Println("CGI处理器启动在 :9090")
http.ListenAndServe(":9090", nil)
}
func handleLogin(w http.ResponseWriter, r *http.Request) {
// 转换原来的Perl登录逻辑
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"status":"success","message":"Login handled by Go"}`))
}
Apache配置:
# 将所有/cgi/*请求转发到Go
<VirtualHost *:80>
ServerName mysite.com
# 转发所有CGI请求
<Location "/cgi/">
ProxyPass http://localhost:9090
ProxyPassReverse http://localhost:9090
</Location>
</VirtualHost>
迁移建议
- 逐步迁移:先转换一个Perl脚本到Go,测试通过后再批量迁移
- 保持API兼容:确保Go端点返回与原来Perl脚本相同格式的数据
- 使用supervisor管理:管理多个Go服务进程
# supervisor配置示例
[program:go_backend]
command=/path/to/your/go-app
directory=/path/to/app
autostart=true
autorestart=true
这种架构允许你保留Apache的虚拟主机管理,同时将业务逻辑逐步迁移到Go,无需一次性重写所有Perl脚本。


