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

3 回复

是的,选择对你来说最有意义的方式。

更多关于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的LocationFilesMatch将特定请求路由到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>

迁移建议

  1. 逐步迁移:先转换一个Perl脚本到Go,测试通过后再批量迁移
  2. 保持API兼容:确保Go端点返回与原来Perl脚本相同格式的数据
  3. 使用supervisor管理:管理多个Go服务进程
# supervisor配置示例
[program:go_backend]
command=/path/to/your/go-app
directory=/path/to/app
autostart=true
autorestart=true

这种架构允许你保留Apache的虚拟主机管理,同时将业务逻辑逐步迁移到Go,无需一次性重写所有Perl脚本。

回到顶部