C#发送POST请求方式及参数被转译解决方法

几天前,工作中有一个小的需求,对接其他公司的人脸识别api。这个需求本身并不复杂,但是中间居然也隐藏了一些不小的坑,最终也让我学到了不少有关于POST、网络请求方面的冷知识,也算是因祸得福了吧。


首先,让我们来看一下对接的文档(未涉及到的参数部分做了删除处理


基本信息

Path: /service/faceidentify/v3
Method: POST

请求参数

Headers

参数名称 参数值 是否必须 示例 备注
Content-Type application/x-www-form-urlencoded

Body

参数名称 参数类型 是否必须 示例 备注
baseimg64 text /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGB 不需要base64文件头

涉及到的就是这些参数了,起初我一看到请求方式POST,立马就拿出之前写的WebHelper工具类,选择了一个POST发送方法来测试发送请求,选择的方法如下:

        public static HttpResult POST(string url, string data, int timeout = 100)
        {
            HttpHelper helper = new HttpHelper();
            HttpItem item = new HttpItem();
            item.Timeout = timeout * 1000;
            item.Encoding = Encoding.UTF8;
            item.POSTEncoding = Encoding.UTF8;
            item.URL = url;
            item.Method = "POST";
            item.POSTDataType = POSTDataType.String;
            item.POSTdata = data;
            item.ContentType = "application/x-www-form-urlencoded";
            HttpResult result = helper.GetHtml(item);
            return result;
        }

返回的结果:414 Request URI too large,看到这个结果我就知道自己错的离谱!!!这种方式的POST其实和get请求没什么区别,都是把参数放到url,只是请求方式是POST而已,我也看到请求参数那里写的是body,更说明了这个接口实际是需要把参数写进body内,url应该就是基本信息中的path,更直观的体现二者差别,可以看看postman这个接口调试软件对二者的区分:

使用Params方式传递参数时,url后面出现了参数值

使用body方式传递参数时,url后面没有参数值

这个接口上传的图片需要转换成base64格式的字符串,于是这种直接把参数写在url内的方式自然就会因为url太长导致对方服务器返回异常了。

于是我又找了另一种方式发送POST请求:

public static string POST(string url, Dictionary<string, string> dic)
        {
            string result = "";
            try
            {
                //添加POST 参数
                System.Text.StringBuilder builder = new System.Text.StringBuilder();
                int i = 0;
                foreach (var item in dic)
                {
                    if (i > 0)
                        builder.Append("&");
                    builder.AppendFormat("{0}={1}", item.Key, item.Value);
                    i++;
                }
                byte[] POSTData = System.Text.Encoding.UTF8.GetBytes(builder.ToString());

                System.Net.HttpWebRequest _webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
                _webRequest.Method = "POST";
                //_webRequest.ContentType = "application/json";
                //内容类型
                _webRequest.ContentType = "application/x-www-form-urlencoded";
                _webRequest.Timeout = 1000 * 30;
                _webRequest.ContentLength = POSTData.Length;

                using (System.IO.Stream reqStream = _webRequest.GetRequestStream())
                {
                    reqStream.Write(POSTData, 0, POSTData.Length);
                    reqStream.Close();
                }

                System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)_webRequest.GetResponse();
                System.IO.Stream stream = resp.GetResponseStream();
                //获取响应内容
                using (System.IO.StreamReader reader = new System.IO.StreamReader(stream, System.Text.Encoding.UTF8))
                {
                    result = reader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("发送POST请求发生异常", ex);
            }
            return result;
        }

可以看到这种方式发送POST请求的时候,是将参数写入到流里面,然后将流作为请求的body发送。请求之后得到以下返回:

至少有json数据返回了

根据返回的数据可以判断:
1. 这次服务器确实收到了我们的请求,并收到了返回
2. 图片参数baseimg64有问题,导致服务器端解析失败
3. 服务器内部问题,这个可能性很小

于是我使用postman重新发送了一遍请求,发现居然识别成功

识别成功!

这样基本就把问题定位在baseimg64这个参数本身了,由于postman的参数是从请求处截下来的,所以能够确认图片转的base64值是没有问题的,那么就是我发的参数和服务器接收的参数不一样,而且postman发送的值虽然和我一样,但是服务器接收到postman发送的值就是正确的。

为了对比我和postman发同样请求时,服务器接受到我们发送的参数有什么不同,我使用flask在我的服务器写了一个类似的接口,将获取到的参数直接在flask的后台打印出来,从而做个对比,接口得python代码如下:

from flask import Flask
from flask import request
import requests
import os

app = Flask(__name__)

@app.route('/',methods=["POST"])
def DownLoad():
    username=request.form['baseimg64']
    print(username)
    return username

if __name__ == '__main__':
    app.run(debug=True,port=1234,host="0.0.0.0")

OK,接下来就分别使用postman和我的程序调用我服务器的flask接口,并将后台打印的获取到的参数值进行对比:

部分参数对比

答案跃然屏幕之上了,是”+”,”+”在我请求的参数中都被替换成为了空格,导致服务器解析的base64图片并不是我发送的图片。根据之前url转译方面的了解,URL中默认的将”+”号转义了。”+”为POST特殊字符,所以传递后会丢失,那么处理方式也就很简单了,要么手动将客户端带”+”的参数中的”+”全部替换为‍”2B%”,这样参数传到服务器端时就能得到”+”了,要么就使用System.Web.HttpUtility.UrlEncode方法将参数先进行编码,从而使服务器端正确的转译出”+”。

小结

这次由工作需求引发的有关POST请求的研究,让我开始关注那些拿来就用的工具类方法,大多数时候拿来就用是没有问题的,或者误打误撞没有错误,但是一旦遇到问题就容易四处起火。同时也希望未来的工作以及编程生涯中,我都能不小看任何一行代码,也不畏惧任何一行代码

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇