一些简单的Post方式WebApi接收参数和传递参数的方法及总结

[删除(380066935@qq.com或微信通知)]

更好的阅读体验请查看原文:https://www.cnblogs.com/zhaimaojun/p/webapi_json.html

原文地址:https://www.zhaimaojun.top/Note/5475297(我自己的博客网站)

各种Post方式上传参数到服务器,服务器接收各种参数的示例

webapi可以说是很常用了,内容也很多,get方式用的多而且很简单,没有说的必要了,但是post方式中,数据从数据体中提取是总是会遇到一些妖魔现象。对此,就我知道的我说一些吧。

作为懒汉,一切繁琐的代码,逻辑,都是累赘,都是看不顺眼的,拖泥带水的代码,逻辑就像强迫症眼里的不规则摆放,总是要解决掉心里才能舒坦的懒。天天幻想着一条代码解决所有问题~

最近有点想注册个bilibili的up主发点代码讲解的视频,我想我能将的比较细致,码字太累了,不符合懒汉的生活习惯,就这短短的文章也是码了一下午才写完的,所以还是讲话来的快,还不耽误玩游戏。

webapi的url组成我就不详细说了,一般都是http://XXX/api/控制器名?参数名=参数值&参数名=参数值

第一种:

接收参数:
[httppost]
public string Get(string p1,[frombody]string p2){
    return p1+p2;
}
c#发送参数:
var p2 = "param2";//p2是需要post传输的
var url = "http://XXX/api/XXX?p1=param1";//p2是来自于post体,所以不再url中
var req= (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";//你没有看错,就是这个
var bts = Encoding.Utf8.GetBytes("="+p2);//划重点!!post方式中application/x-www-form-urlencoded传输方式下,frombody的参数只能有一个!而在body中你要是用key=value方式传递参数,那么接收端收到的全都是null。
req.ContentLenth = bts.Lenth;//划重点!!post方式必须设置这个值
var st = req.GetResquestStream();
st.Write(bts,0,bts.Lenth);//划重点!!post方式必须要往body中写入数据
var res= (HttpWebResponse)req.GetResponse();
ajax提交参数:
var url = "http://XXX/api/XX?p1=param1"
var p2 = "param2"
$.post(url, "="+p2, function(res){
    alert(res);
});
微信小程序提交参数(JavaScript):
var p2 = "param2";
wx.request({
    url: 'http://XXX/api/XX?p1=param1',
    method: 'POST',
    header: {'content-type': 'application/x-www-form-urlencoded'},//或者不写这行
    data: "=" + p2,
    success(re){
        console.log(re);
    }
});
这种方式的注意点:
很早前我学习api的时候就遇到了参数始终为null的苦恼,当时也没有相关的资料可以查阅,百度到的内容都七七八八,都说不到重点上,最后不知道在哪个网站上看见了有个人也是同样的问题,有人提到说是=号前面不要参数名,我尝试了,还真就解决问题了,于是我写了哪一篇博文,到现在三年多了,被好多人转载了。说明大家都被这个问题折磨了很久啊哈哈哈,其实要点很简单,就是body中只要一个参数的值,且=号开始,=号前面不写参数名,=号后面的所有内容都会被读取为唯一的那个frombody的参数内容。就是这样的。要知道api只能有一个参数是frombody的!

第二种:

接收参数:
[httppost]
public string Post(string p1){
    var p2 = HttpContext.Current.Request.Form["p2"];
    var p3 = HttpContext.Current.Request.Form["p3"];
    if(HttpContext.Current.Request.Files.Lenth > 0){
        var fs = HttpContext.Current.Request.Files[0];
        fs.SaveAs(HttpContext.Current.Server.MapPath("~/data.txt"));
    }
    return p1+p2+p3;//上传的混合参数
}

c#发送参数:

        private string UploadFileAndParams(string serverIp, int serverPort, string rowurl, string filename, Dictionary<string, string> otherparams)
        {
            try
            {
                //打开socket连接
                Socket httpsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                httpsocket.Connect(serverIp, serverPort);
                //计算得出总的一个请求
                //请求的头部
                string httprequestheader = "POST " + rowurl + " HTTP/1.1\r\n";
                httprequestheader += "Host: " + serverIp + ":" + serverPort + "\r\n";
                //httprequestheader += "Content-Length: " + "\r\n";//计算并添加数据长度,这里的数据长度是总的长度
                httprequestheader += "Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp\r\n";
                httprequestheader += "Connection: Keep-Alive\r\n";
                //发送文件
                string httpFileheader = "--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp\r\n";
                httpFileheader += "Content-Disposition: attachment; name=text; filename=" + Path.GetFileName(filename) + "\r\n";
                httpFileheader += "Content-Type: application/octet-stream\r\n";
                httpFileheader += "Content-Transfer-Encoding: binary\r\n";
                httpFileheader += "\r\n";
                byte[] Bfileheader = Encoding.UTF8.GetBytes(httpFileheader);
                //这里需要发送文件的内容,二进制
                FileStream localfile = new FileStream(filename, FileMode.Open);
                //发送其他参数
                var lBParamheaders = new List<byte[]>();
                foreach (var item in otherparams)
                {
                    string paramstr = "--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp\r\n";
                    paramstr += "Content-Disposition: form-data; name=" + item.Key + "\r\n";
                    paramstr += "Content-Type: text/plain; charset=UTF-8\r\n";
                    paramstr += "\r\n";
                    paramstr += item.Value + "\r\n";
                    lBParamheaders.Add(Encoding.UTF8.GetBytes(paramstr));
                }
                byte[] Bendbody = Encoding.UTF8.GetBytes("--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp--\r\n");
                //统计总长度
                long lenth = Bfileheader.Length + localfile.Length + Bendbody.Length + 2;
                foreach (var item in lBParamheaders)
                    lenth += item.Length;
                httprequestheader += "Content-Length: " + lenth + "\r\n";//计算并添加数据长度,这里的数据长度是总的长度
                httprequestheader += "\r\n";
                byte[] Brequestheader = Encoding.UTF8.GetBytes(httprequestheader);
                //开始发送请求
                string sv = Encoding.UTF8.GetString(Brequestheader);
                httpsocket.Send(Brequestheader);//发送头
                sv += Encoding.UTF8.GetString(Bfileheader);
                httpsocket.Send(Bfileheader);//发送文件头
                //发送文件
                for (long i = 0; i < localfile.Length;)
                {
                    int len = ((localfile.Length - i) &gt; 30000) ? 30000 : (int)(localfile.Length - i);
                    byte[] bt = new byte[len];
                    localfile.Read(bt, 0, len);
                    sv += Encoding.UTF8.GetString(bt);
                    httpsocket.Send(bt);
                    i += len;
                }
                sv += "\r\n";
                httpsocket.Send(Encoding.UTF8.GetBytes("\r\n"));
                //发送其他参数
                foreach (var item in lBParamheaders)
                {
                    sv += Encoding.UTF8.GetString(item);
                    httpsocket.Send(item);
                }
                sv += Encoding.UTF8.GetString(Bendbody);
                httpsocket.Send(Bendbody);
                //等待服务器返回结果:
                byte[] result = new byte[30000];
                int reslen = httpsocket.Receive(result);
                //处理并返回结果
                string resultstr = Encoding.UTF8.GetString(result, 0, reslen);
                int idex = resultstr.IndexOf("\r\n\r\n");
                string resstr = resultstr.Substring(idex);
                localfile.Close();
                httpsocket.Close();
                return resstr;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
//使用:
var pms = new Dictionary<string, string>();
pms.Add("p2","param2");
pms.Add("p3","param3");
var result = UploadFileAndParam("192.168.1.1",8088,"/api/XX?p1=param1","指定一个本地要上传的文件名",pms);

ajax提交参数(html):

    <form method="post" action="/api/XXX?p1=param1">
        <div class="form-group input-group">
            <input name="p2" class="form-control" value="param2" type="text" />
            <input name="p3" class="form-control" value="param3" type="text" />
            <input name="文件名不重要" class="form-control" type="file" accept="image/png, image/jpeg(这里要写上传的文件的类型)" />
            <span class="input-group-btn">
                <button class="btn btn-default" type="submit">
                    <span class="glyphicon glyphicon-search"></span>上传
                </button>
            </span>
        </div>
    </form>

微信小程序提交参数(JavaScript):

wx.chooseImage({
  success (res) {
    const tempFilePaths = res.tempFilePaths
    wx.uploadFile({
      url: 'http://xxx/api/XX?p1=param1',
      filePath: tempFilePaths[0],
      name: '文件名',
      formData: {
        'p2': 'param2',
        'p3': 'param3'
      },
      success (res){
        console.log(res);
      }
    })
  }
})

这种方式的注意点:

这就是传统的mvc的页面提交方式,是带文件的提交方式,这里要注意的就是,c#部分我贴的代码其实不是http请求,而是socket连接,也就是说,他不限制平台,比如一个单片机,接上一个能够联网且创建socket的模块,不需要实现http协议,就可以直接将数据发送给服务器,然后收到服务器的回复!市场上常用的nbiot模块或者以太网模块或者wifi模块,只要能连接服务器并且创建socket连接,就可以,我当初就是拿这套代码改成c语言版本后跑在单片机上,通过bc35模块连接云服务器的。

第三种:

接收参数:

public struct SomeData{//struct的名称其实不重要
    public string p2{get;set;}//注意,get;set;这种属性很重要,如果不是属性很可能参数一直为null!
    public int p3{get;set;}
}
[httppost]
public string Get(string p1,[frombody]SomeData sd){//这里的参数名不重要
    return p1+sd.p2+sd.p3;//所有的混合参数
}

c#发送参数:

//代码中使用到了Newtonsoft.Json包,请自行下载安装
        public string PostData(string url, object o)
        {
            try
            {
                var dts = Newtonsoft.Json.JsonConvert.SerializeObject(o);//先将object转为json字符串
                var data = Encoding.UTF8.GetBytes(dts);//再将字符串转换为byte[]
                var hr= (HttpWebRequest)WebRequest.Create(url);
                hr.Method = "POST";
                hr.ContentType = "application/json";
                hr.ContentLength = data.Length;
                using (var rs = hr.GetRequestStream()) rs.Write(data, 0, data.Length);
                using (WebResponse hp = hr.GetResponse())
                using (Stream s = hp.GetResponseStream())
                {
                    var res = new StreamReader(s).ReadToEnd();
                    return res;
                }
            }
            catch (Exception)
            {
                return null;
            }
        }
//使用:
var result = PostData("http://XXX/api/XX?p1=param1",new { p2 = "param2", p3 = 333 });

ajax提交参数:

var url = "http://XXX/api/XX?p1=param1"
var pms = {
    p2 : "p2",
    P3 : 333,
}
$.post(url, pms, function(res){
    alert(res);
});

微信小程序提交参数(JavaScript):

var pms = {
    p2 : "param2",
    p3 : 333,
}
wx.request({
    url: 'http://XXX/api/XX?p1=param1',
    method: 'POST',
    header: {'content-type': 'application/json;charset=UTF-8'},
    data: pms,
    success(re){
        console.log(re);
    }
});

这种方式的注意点:

这种方式就是现在很流行的json数据通讯方式,这种方式下,微信小程序,ajax等都支持,且代码简洁,比较常用,但是也要注意,就是struct中的内容最好都是get;set;的属性,我之前用变量的方式好像也能收到参数,但是后来又发现不能收到参数,也可能是不同的.net版本导致的,服务器端需要安装Newtonsoft.Json包,一般都会自带有一个旧版本的包,最好还是更新一下。c#传递参数时就必须要用到Newtonsoft.Json包的,如果是wpf项目是不会自带这个包的。安装这个包也很简单,就是到nuget包管理器中搜索然后安装就行了。

各种服务器返回数据后本地解析数据的示例

第一种:

服务器返回:

public string Get(string p1){//返回值就是普通的常用的类型,比如string,int,long,double,等等
    return p1;
}

c#解析数据:

var req= (HttpWebRequest)WebRequest.Create("http://xxx/api/xx?p1=1");
var res= (HttpWebResponse)req.GetResponse();
var result = int.TryParse(res, out var v) ? v : default;//非string就用指定的类型TryParse,如果是string,注意了,其中会包含两个双引号,所以结果应该需要replace比如:
var result = res.Trim('\"');//res.Replace("\"",string.Empty);

微信小程序/ajax解析数据:

wx.request({
    url: 'http://XXX/api/XX?p1=param1',
    success(re){
        console.log(re.data);//re基本都是字符串类型,所以直接可以用来判断,如果服务器返回的是string类型,则注意re.data中会有两个双引号一前一后,需要去除掉
    }
});

这种方式的注意点:

这种方式对微信ajax等平台不友好,数据返回比较单一,且都是字符串,需要自己去解析内容,比较不方便,虽然服务器返回数据方便,但是对数据的使用者来说造成了麻烦。

第二种:

服务器返回:

public IHttpActionResult Get(string p1){//学过mvc的应该很眼熟吧,没错,就是和mvc的返回方式是一样的!
    return Json(new { dt1 = "data1", dt2 = 2345 });//这是返回的是纯json,可以返回任意的对象,json中包括了对象的所有可读的属性。当然,你也可以返回数组,字典,List,struct等等你想返回的东西
    var fp = HttpContent.Current.Server.MapPath("~/file/p1.jpg");
    return File(fp,MimeMapping.GetMimeMapping(fp),"当我们点击下载时显示的名称.jpg");//这是返回任意的文件,其他更多的方式可参考mvccontroler
}

c#解析数据:

//服务器返回文件时可以直接下载就可以了:
var result = new WebClient().DownloadFile ("http://xxx/api/xx?p1=","指定一个本地的保存文件的地址");
//如果服务器返回的是一个对象,数组,struct,List等时:
public struct SomeData{
    public string dt1{get;set;}
    public int dt2{get;set;}
}
var hr= (HttpWebRequest)WebRequest.Create("http://xxx/api/xx?p1=1");
var hp = hr.GetResponse();
var s = hp.GetResponseStream();
var res = new StreamReader(s).ReadToEnd();
try{ return Newtonsoft.Json.JsonConvert.DeserializeObject<SomeData>(res); }
catch { return default; }//返回值就是一个struct,当然,上面的SomeData可以是其他的类型,如果json反序列化失败则会抛出异常,然后返回default,返回一个缺省的值。


微信小程序/ajax解析数据:

//如果是文件:
wx.downloadFile({//(摘自微信公众平台:https://developers.weixin.qq.com/miniprogram/dev/api/network/download/wx.downloadFile.html)
  url: 'http://xxx/api/xx?p1=', //仅为示例,并非真实的资源
  success (res) {
    // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
    if (res.statusCode === 200) {
      wx.playVoice({
        filePath: res.tempFilePath
      })
    }
  }
})
//如果返回的是纯json内容:
wx.request({
    url: 'http://XXX/api/XX?p1=param1',
    success(re){
        console.log(re.data);
        if(re.data.dt1) console.log(re.data.dt1);//可以直接访问属性的,不需要做其他的事情,因为返回的纯json是已经解析后的数据,如果是数组或者list,可以直接each,非常方便
        if(re.data.dt2) console.log(re.data.dt2);
    }
});

这种方式的注意点:

这种方式对ajax,微信等非常友好,兼容性很好,可以直接互相传递对象,容器数组等等,都是标准的文件或者json对象,也是主流的趋势,兼容多种平台。所以推荐使用。

估计有了这两种方法基本满足了。