Golang中bufio.NewReader将空格转换为加号的问题探讨

Golang中bufio.NewReader将空格转换为加号的问题探讨 我正在运行 go 版本 go1.12.1 windows/amd64 我的笔记本电脑是 Windows 10 64 位 我编写了一个 GO 程序,作为 Apache 网页服务器下的 CGI 脚本运行。

我的网页上的一个表单通过 POST 方法向 GOlang CGI 脚本程序提交了一个请求。

令我惊讶的是,数据字段中的空格被更改为了加号。

我使用 bufio.NewReader 来读取包含 POST 方法数据的标准输入,代码如下:

		reader := bufio.NewReader(os.Stdin)
		for {
			looptext, _ := reader.ReadString('\n')
			count := len(looptext)
			if count == 0 {
				break
			}
			post_data += looptext + "\n"
			post_vars := strings.Split(looptext, "&")
			for _, pvar := range post_vars {
				pair := strings.SplitN(pvar, "=", 2)
				fields_count += 1
				fields_map[pair[0]] = pair[1]
			}
		} // FOR over lines of POST data

为什么空格被改成了加号?到目前为止,谷歌搜索还没有找到任何相关信息。


更多关于Golang中bufio.NewReader将空格转换为加号的问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

感谢您的回复。我已经非常习惯使用 Perl 进行 CGI 编程,因为 Perl 的 CGI 库会为我处理所有的解码工作。

我添加了对 url.QueryUnescape() 的调用,现在数据完全符合预期。再次感谢。

更多关于Golang中bufio.NewReader将空格转换为加号的问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


请向我们展示POST请求的头部和主体。

同时,请查看百分比编码 - 维基百科

默认使用的编码基于早期版本的通用URI百分比编码规则,并进行了一些修改,例如换行符标准化以及**将空格替换为+**而不是%20

这是一个典型的表单编码问题,不是 bufio.NewReader 的转换。当表单通过 application/x-www-form-urlencoded 编码(默认编码)提交时,空格会被转换为加号(+)。

在 URL 编码规范中:

  • 空格被编码为 +
  • 其他特殊字符被编码为 %XX 十六进制格式

你需要对接收到的值进行 URL 解码。使用 url.QueryUnescape() 函数:

package main

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

func main() {
    fields_map := make(map[string]string)
    
    reader := bufio.NewReader(os.Stdin)
    for {
        looptext, _ := reader.ReadString('\n')
        looptext = strings.TrimRight(looptext, "\r\n")
        
        if len(looptext) == 0 {
            break
        }
        
        post_vars := strings.Split(looptext, "&")
        for _, pvar := range post_vars {
            pair := strings.SplitN(pvar, "=", 2)
            if len(pair) == 2 {
                // 解码 URL 编码的值
                decodedValue, err := url.QueryUnescape(pair[1])
                if err != nil {
                    decodedValue = pair[1] // 如果解码失败,使用原始值
                }
                fields_map[pair[0]] = decodedValue
            }
        }
    }
    
    // 测试输出
    for key, value := range fields_map {
        fmt.Printf("%s: %s\n", key, value)
    }
}

或者,更简洁的方法是使用 url.ParseQuery()

package main

import (
    "bufio"
    "fmt"
    "io"
    "net/url"
    "os"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    var input strings.Builder
    
    // 读取所有输入
    for {
        line, err := reader.ReadString('\n')
        if err != nil && err != io.EOF {
            break
        }
        input.WriteString(line)
        if err == io.EOF {
            break
        }
    }
    
    // 解析查询字符串
    values, err := url.ParseQuery(input.String())
    if err != nil {
        fmt.Printf("解析错误: %v\n", err)
        return
    }
    
    // 访问解码后的值
    for key := range values {
        fmt.Printf("%s: %s\n", key, values.Get(key))
    }
}

如果你需要处理 multipart/form-data 编码(用于文件上传),则需要使用不同的方法:

package main

import (
    "fmt"
    "mime"
    "mime/multipart"
    "net/http"
    "os"
    "strings"
)

func main() {
    // 从环境变量获取内容类型
    contentType := os.Getenv("CONTENT_TYPE")
    
    if strings.Contains(contentType, "multipart/form-data") {
        // 处理 multipart 表单
        reader := multipart.NewReader(os.Stdin, strings.Split(contentType, "boundary=")[1])
        for {
            part, err := reader.NextPart()
            if err != nil {
                break
            }
            defer part.Close()
            
            // 处理每个部分
            data := make([]byte, 1024)
            n, _ := part.Read(data)
            fmt.Printf("%s: %s\n", part.FormName(), string(data[:n]))
        }
    } else {
        // 处理 application/x-www-form-urlencoded
        // 使用上面的 url.ParseQuery 方法
    }
}

关键点:

  1. bufio.NewReader 只是读取原始数据,不会修改内容
  2. 空格变加号是表单提交时的标准 URL 编码行为
  3. 使用 url.QueryUnescape()url.ParseQuery() 进行解码
  4. 检查 CONTENT_TYPE 环境变量来确定编码方式
回到顶部