You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言net/url库解析含#号密码的数据库连接串失败如何解决?

Go net/url库解析含特殊字符的PostgreSQL连接串解决方案

问题根因

你的推测完全符合URL规范定义:# 是URL的片段标识符起始标记,解析时会直接截断#之前的所有路径/认证信息逻辑,所以密码中明文出现#时会导致用户认证段识别失败。

方案1:构造连接串时提前编码密码(推荐)

如果是你自己拼接生成数据库连接串,直接用url.QueryEscape()对密码做URL编码即可,所有URL保留字符(#、@、/、:、?等)都会被自动转义,无需单独处理特殊字符。
代码示例:

package main

import (
    "fmt"
    "net/url"
)

func main() {
    username := "postgres"
    rawPassword := "password#"
    // 对密码做URL编码
    escapedPassword := url.QueryEscape(rawPassword)
    // 拼接连接串
    connString := fmt.Sprintf("postgresql://%s:%s@192.168.1.10:5432/postgres", username, escapedPassword)
    parsedUrl, err := url.Parse(connString)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("=")
    fmt.Println(parsedUrl.User)
    // 要获取明文密码可以调用Password()方法
    password, _ := parsedUrl.User.Password()
    fmt.Println("解析出的明文密码:", password)
    fmt.Println("=")
}

执行结果:

$ go run main.go
=
postgres:password#
解析出的明文密码: password#
=

方案2:预处理已生成的明文连接串

如果拿到的连接串已经是明文带特殊字符、无法修改生成逻辑的,可以先提取用户认证段做转义后再拼接解析:
代码示例:

package main

import (
    "fmt"
    "net/url"
    "strings"
)

func escapeUserInfoInConnStr(connStr string) string {
    // 拆分scheme和剩余部分
    schemeSplit := strings.SplitN(connStr, "://", 2)
    if len(schemeSplit) != 2 {
        return connStr
    }
    scheme := schemeSplit[0]
    rest := schemeSplit[1]
    // 找@的位置,拆分用户信息和主机部分
    atIndex := strings.Index(rest, "@")
    if atIndex == -1 {
        return connStr
    }
    userInfo := rest[:atIndex]
    hostPart := rest[atIndex:]
    // 拆分用户名和密码分别转义再拼接
    userPassSplit := strings.SplitN(userInfo, ":", 2)
    if len(userPassSplit) == 2 {
        user := userPassSplit[0]
        pass := userPassSplit[1]
        escapedUser := url.QueryEscape(user)
        escapedPass := url.QueryEscape(pass)
        userInfo = fmt.Sprintf("%s:%s", escapedUser, escapedPass)
    } else {
        userInfo = url.QueryEscape(userInfo)
    }
    return fmt.Sprintf("%s://%s%s", scheme, userInfo, hostPart)
}

func main() {
    connString := "postgresql://postgres:password#@192.168.1.10:5432/postgres"
    // 先预处理连接串
    processedConnStr := escapeUserInfoInConnStr(connString)
    parsedUrl, err := url.Parse(processedConnStr)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("=")
    fmt.Println(parsedUrl.User)
    fmt.Println("=")
}

执行结果与方案1一致,可正常解析出用户凭证。

内容的提问来源于stack exchange,提问作者atline

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 15:06:02