HttpWebRequest无法发送“+”字符

3
我正在尝试使用POST请求发送Base64编码的数据,其中包含“+”字符。当我发送请求时,“+”被替换为空格。以下是代码:
    public string POST(string url, string query)
    {
        HttpWebRequest hwrq = CreateRequest(url);
        hwrq.CookieContainer = Cookies;
        hwrq.Method = "POST";
        hwrq.ContentType = "application/x-www-form-urlencoded";
        byte[] data = Encoding.Default.GetBytes(query);
        hwrq.ContentLength = data.Length;
        hwrq.GetRequestStream().Write(data, 0, data.Length);
        using (HttpWebResponse hwrs = (HttpWebResponse)hwrq.GetResponse())
        {
            using (StreamReader sr = new StreamReader(hwrs.GetResponseStream()))
            {
                return sr.ReadToEnd().Trim();
            }
        }
    }

    public HttpWebRequest CreateRequest(string url)
    {
        HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(url);
        Request.UserAgent = UserAgent;
        Request.Accept = Accept;
        Request.Headers.Add("Accept-Language", AcceptLang);
        Request.AutomaticDecompression = DMethod;
        return Request;
    }

我一直在追踪“query”变量,它带有“+”字符,但当我在嗅探器(Charles)中查看请求时,请求被发送时没有“+”符号。
例如,我正在尝试发送

<...>zxJ+zZq<...>

但实际发送的是

<...>zxJ zZq<...>

我做错了什么?
提前感谢您的回答。

3个回答

10

+代表查询字符串中的空格。看起来你发送的query变量没有正确进行URL编码。不幸的是,你没有展示如何构造这个query字符串变量,但以下是确保所有值正确进行URL编码的正确方式:

var values = HttpUtility.ParseQueryString(string.Empty);
values["foo"] = "some + value";
values["bar"] = "some other value";
string query = values.ToString();
// query will equal foo=some+%2b+value&bar=some+other+value

注意原来的值中的加号 + 被编码为 %2B

如果您写以下内容:

string query = "foo=some + value&bar=some other value";

我认为您已经看出了问题,并且注意到了正确的查询字符串与错误查询字符串之间的差异,正确的查询字符串是foo=some+%2b+value&bar=some+other+value

既然如此,这是我建议您改进代码的方法。您可以扩展WebClient类以处理Cookie,具体操作如下:

public class WebClientEx : WebClient
{
    public CookieContainer Cookies { get; private set; }
    public WebClientEx()
    {
        Cookies = new CookieContainer();
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = (HttpWebRequest)base.GetWebRequest(address);
        request.CookieContainer = Cookies;
        return request;
    }
}

现在简单地说:

using (var client = new WebClientEx())
{
    client.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0";
    client.Headers[HttpRequestHeader.AcceptLanguage] = "en-us,en;q=0.5";
    var values = new NameValueCollection
    {
        { "foo", "some value" },
        { "bar", "some & other + value =" },
    };
    byte[] buffer = client.UploadValues("http://www.example.com", values);
    string result = Encoding.UTF8.GetString(buffer);
}

看看这样相比于搞所有的HttpWebRequests、响应、流、编码等等,这是多么容易啊...?


WPF 4.5 应用程序运行得非常好。 - Hafiz H
非常感谢,它起作用了,我得到了这个值:$_POST['foo']; - Arash.Zandi

1
表单数据以 URL 编码的形式发送,空格被编码为 +,因此 + 将被解码为空格。
使用 Server.UrlEncode 方法对要发送的数据进行编码。

0

尝试使用不同的内容类型:

hwrq.ContentType = "text/plain";

在你的例子中,你发布了原始的base64数据(纯文本),但是你告诉远程服务器你正在发布一个url编码的查询字符串(application/x-www-form-urlencoded)。这就是为什么远程服务器尝试对你的base64数据进行url解码,这将用空格替换+号的原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接