C#调用接口注意要点
在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用,
所以首先需要通过调用登录接口来保存cookie值,再进行其他接口的调用
1.通过Get方式
#region get方式 public string HttpGet(string url) { Encoding encoding = Encoding.UTF8; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; request.ContentType = "application/json"; request.Headers["Accept-Encoding"] = "gzip,deflase"; request.AutomaticDecompression = DecompressionMethods.GZip; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // HttpCookie cookies = new HttpCookie("admin"); //如果有需要通过登录实现保存cookie值的话可以加一部分 // cookies.Value = Convert.ToString(response.Headers["Set-Cookie"]); // 通过响应请求读取带cookie的http数据 // cookies.Expires = DateTime.Now.AddDays(1); // HttpContext.Current.Response.Cookies.Add(cookies); using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { return reader.ReadToEnd(); } } #endregion
但是并不是所有的get请求都需要添加这个heard的内容,有些加了这个可能出现乱码的情况,所以不要设置Accept-Encoding的Header
此处之所以加此header,是因为看到网页分析工具中所得到的浏览器浏览该网页,对应的http的header的内容中,就是这样设置的。
所以,代码中,也是模拟浏览器去访问网页,就设置了对应的Accept-Encoding为gzip,deflate了
普通浏览器访问网页,之所以添加:"Accept-Encoding" = "gzip,deflate"
那是因为,浏览器对于从服务器中返回的对应的gzip压缩的网页,会自动解压缩,所以,其request的时候,添加对应的头,表明自己接受压缩后的数据。
同时添加了 request.AutomaticDecompression = DecompressionMethods.GZip;这一句,便可以获得正确的数据。
如果你获取网页内容太大的话,那么还是可以用这个办法的,这样就可以让HttpWebRequest自动帮你实现对应的解压缩了,可以减少数据数据传输量,节省时间,提高效率。
2.通过post方式
public string HttpPost2(string url, string body) { //把用户传过来的数据转成“UTF-8”的字节流 Encoding encoding = Encoding.UTF8; //先根据用户请求的uri构造请求地址 //创建Web访问对象 HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url); request.Method = "POST"; // request.Accept = "application/json"; request.ContentType = "application/json; charset=UTF-8"; request.Headers["Accept-Encoding"] = "gzip, deflate"; request.AutomaticDecompression = DecompressionMethods.GZip; //HttpCookie Cookie = System.Web.HttpContext.Current.Request.Cookies["admin"]; //若是需要登录过后再能访问获取url的数据,需要在请求头中设置cookie值 //if (Cookie != null) // request.Headers.Add("Cookie", Cookie.Value.ToString()); byte[] buffer = encoding.GetBytes(body); request.ContentLength = buffer.Length; request.GetRequestStream().Write(buffer, 0, buffer.Length); //通过Web访问对象获取响应内容 HttpWebResponse response = (HttpWebResponse) request.GetResponse(); //通过响应内容流创建StreamReader对象,因为StreamReader更高级更快 using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { return reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾 } }
3.通过put请求
#region Put请求 public string Put(string data, string uri) {//创建Web访问对象 HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(uri); //把用户传过来的数据转成“UTF-8”的字节流 byte[] buf = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(data); Request.Method = "PUT"; Request.ContentLength = buf.Length; Request.ContentType = "application/json"; Request.MaximumAutomaticRedirections = 1; Request.AllowAutoRedirect = true; //发送请求 Stream stream = Request.GetRequestStream(); stream.Write(buf, 0, buf.Length); stream.Close(); //获取接口返回值 //通过Web访问对象获取响应内容 HttpWebResponse Response = (HttpWebResponse)Request.GetResponse(); //通过响应内容流创建StreamReader对象,因为StreamReader更高级更快 StreamReader reader = new StreamReader(Response.GetResponseStream(), Encoding.UTF8); //string returnXml = HttpUtility.UrlDecode(reader.ReadToEnd());//如果有编码问题就用这个方法 string returnXml = reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾 reader.Close(); Response.Close(); return returnXml; } #endregion
4.通过Delete请求
#region Delete请求 public string Delete(string data, string uri) { //创建Web访问对象 HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(uri); //把用户传过来的数据转成“UTF-8”的字节流 byte[] buf = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(data); Request.Method = "DELETE"; Request.ContentLength = buf.Length; Request.ContentType = "application/json"; Request.MaximumAutomaticRedirections = 1; Request.AllowAutoRedirect = true; //发送请求 Stream stream = Request.GetRequestStream(); stream.Write(buf, 0, buf.Length); stream.Close(); //获取接口返回值 //通过Web访问对象获取响应内容 HttpWebResponse Response = (HttpWebResponse)Request.GetResponse(); //通过响应内容流创建StreamReader对象,因为StreamReader更高级更快 StreamReader reader = new StreamReader(Response.GetResponseStream(), Encoding.UTF8); //string returnXml = HttpUtility.UrlDecode(reader.ReadToEnd());//如果有编码问题就用这个方法 string returnXml = reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾 reader.Close(); Response.Close(); return returnXml; } #endregion
不同的场景需求,使用不同的方式,应用在不同的场景 。
通过这几种组合方式 ,可以调用http接口,完成调用和测试。
socket,模拟服务器、客户端通信
服务器代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Missuin
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//当点击开始监听的时候 在服务器端创建一个负责监IP地址和端口号的Socket
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
IPAddress ip = IPAddress.Any;//IPAddress.Parse(txtServer.Text);
//创建端口号对象
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//监听
socket.Bind(point);
ShowMsg("监听成功");
socket.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socket);
}
Socket socketSend;
/// <summary>
/// 被线程所执行的函数,只能传object参数
/// </summary>
/// <param name="o"></param>
void Listen(Object o)
{
Socket socketWatch = o as Socket;
//等待客户端连接 并创建一个负责通信的Sokcet
while (true)
{
//负责根客户通信的Socket
socketSend = socketWatch.Accept();
dictSocket.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
cbuUsers.Items.Add(socketSend.RemoteEndPoint.ToString());
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "连接成功");
////客户端连接成功后,服务器应该接受客户端发来的消息
//byte[] buffer = new byte[1024 * 1024 * 2];
////实际接受到的有效字节数
//int r = socketSend.Receive(buffer);
//string str = Encoding.UTF8.GetString(buffer, 0, r);
//Console.WriteLine(socketSend.RemoteEndPoint+":"+str);
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start(socketSend);
}
}
Dictionary<String, Socket> dictSocket = new Dictionary<string, Socket>();
/// <summary>
/// 服务器端不修改的接收客户发来的消息
/// </summary>
/// <param name="o"></param>
void Recive(object o)
{
Socket socketSend = o as Socket;
while (true)
{
try
{
//客户端连接成功后,服务器应该接受客户端发来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
//实际接受到的有效字节数
int r = socketSend.Receive(buffer);
if (r == 0)
break;
string str = Encoding.UTF8.GetString(buffer, 0, r);
ShowMsg(socketSend.RemoteEndPoint + ":" + str);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
void ShowMsg(string msg)
{
txtLog.AppendText(msg + "\r\n");
}
private void Form2_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
/// <summary>
/// 服务器给客户端发消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{
byte[] msgs = Encoding.UTF8.GetBytes(this.txtmsg.Text);
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(msgs);
byte[] newmsgs = list.ToArray();
//获得用户在下拉框中选中的IP地址
string ip = cbuUsers.SelectedItem.ToString();
Socket sendSocket = dictSocket[ip];
sendSocket.Send(newmsgs);
ShowMsg(sendSocket.RemoteEndPoint + ":" + this.txtmsg.Text);
}
/// <summary>
/// 选择要发送的文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSelect_Click(object sender, EventArgs e)
{
OpenFileDialog of = new OpenFileDialog();
of.InitialDirectory = @"C:\users";
of.Title = "请选择要发送的文件";
of.Filter = "所有文件|*.*";
of.ShowDialog();
txtPath.Text = of.FileName;
}
private void btnFileSend_Click(object sender, EventArgs e)
{
string path = this.txtPath.Text.ToString();
using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024 * 1024 * 5];
List<byte> list = new List<byte>();
list.Add(1);
list.AddRange(list);
byte[] newBytes = list.ToArray();
Socket socket = dictSocket[cbuUsers.SelectedItem.ToString()];
socket.Send(newBytes);
}
}
private void button3_Click(object sender, EventArgs e)
{
byte[] buffer = new byte[1];
buffer[0] = 2;
Socket socket = dictSocket[cbuUsers.SelectedItem.ToString()];
socket.Send(buffer);
}
}
}
客户端代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//创建负责通信的Socket
Socket socketSend;
private void button1_Click(object sender, EventArgs e)
{
try
{
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(textBox1.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(textBox2.Text));
socketSend.Connect(point);
showMsg("连接成功");
//开启一个新线程不停的接收服务器发来的消息
Thread th = new Thread(recive);
th.IsBackground = true;
th.Start();
}
catch(Exception ex)
{
}
}
/// <summary>
/// 不停的接收服务器发来的消息
/// </summary>
void recive()
{
while (true)
{
byte[] buffer = new byte[1024 * 1024 * 2];
int r = socketSend.Receive(buffer);
if (r == 0)
break;
//发来的是文字
if (buffer[0] == 0)
{
string s = Encoding.UTF8.GetString(buffer,1,r-1);
showMsg(socketSend.RemoteEndPoint + ":" + s);
}
else if (buffer[0] == 1)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.InitialDirectory = @"C:\";
sfd.Title = "请选择要保存的文件";
sfd.Filter = "所有文件|*.*";
sfd.ShowDialog(this);
string path = sfd.FileName;
using(FileStream sf = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
{
sf.Write(buffer, 1, r - 1);
}
MessageBox.Show("保存成功");
}
else if (buffer[0] == 2)
{
for (int i=0;i<10;i++){
this.Location = new Point(200, 200);
this.Location = new Point(210, 210);
}
}
}
}
private void showMsg(string msg)
{
this.txtLog.AppendText(msg + "\r\n");
}
private void button2_Click(object sender, EventArgs e)
{
byte[] msgs = System.Text.Encoding.UTF8.GetBytes(txtmsg.Text);
socketSend.Send(msgs);
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
}
}
在ASP.NET Core中构建路由的5种方法
原文链接 :https://stormpath.com/blog/routing-in-asp-net-core
在ASP.NET Core中构建路由的5种方法
by Team Stormpath | August 17, 2016 |
在软件开发中,路由用于将所有传入请求映射到处理程序,并生成响应中使用的URL。在ASP.NET Core中,路由已经从根本上重写了。以前,使用MVC和Web API进行路由非常相似,但两者都使用不同的框架(和代码)来执行相同的操作。一个重要的区别是Web API默认支持RESTful路由。例如,如果一个控制器的操作方法名称开头Post,那么调用一个HTTP Post默认情况下会调用该方法。
由于微软决定重建和统一路由框架,现在适用于MVC,也适用于Web API。然而,在我们深入了解如何构建路由之前,让我们回顾一下为什么路由对您的应用程序非常重要。
为什么路由?
SEO友好
REST式配置的路由有助于您的内容的搜索引擎优化(SEO)。网站的网址是影响网站排名的首要标准之一。通过将www.yourwebsite.com/articles/show/123转换为www.yourwebsite.com/how-to-peel-potatoes,您鼓励搜索引擎对与“how to peel potatoes.”有关的关键语句进行排名。
此外,如果您的网址具有更强的描述性,则用户可以更轻松地预测内容,从而增加页面上的时间,这也会影响SEO和整体页面权限。
网址不需要映射文件
没有路由,传入的请求将被映射到物理文件。通过路由,我们可以完全控制请求,使我们能够决定在某个HTTP请求进入时我们执行的操作和控制器。
长URL和文件扩展名可以省略
在许多参数和过滤器都在使用的情况下,路由有助于缩短URL。通过消除文件扩展名,我们可以隐藏我们正在工作的环境。
那么,我们如何利用这些好处呢?让我们看看您可以在ASP.NET Core应用程序中构建路由的五种方法。
1.创建默认路由
您可以按照惯例在您的项目Startup类中定义默认路由。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseMvc(routes => { routes.MapRoute( name: "default", template: " {controller=Home}/{action=Index}/{id?}"); }); } } |
通过以上,我们确保我们项目中的基本配置存在于Controller + Action + ID(可选)路径的标准MVC模式中。你也可以像这样声明路由模式:
1 2 3 4 5 6 |
routes.MapRoute( name: "default_route", template: "{controller}/{action}/{id?}", defaults: new { controller = "Home", action = "Index" } ); |
(这是我们用来在ASP.NET Core中进行路由的方式。)
2.扩展默认路由
一旦我们配置了默认路由,我们可能希望通过根据特定需求添加自定义路由来扩展它。为此,我们可以使用该MapRoute()方法添加配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
app.UseMvc(routes => { //New Route routes.MapRoute( name: "about-route", template: "about", defaults: new { controller = "Home", action = "About" } ); routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); |
我们添加了一条额外的路线,通过路线授予对主控制器上“关于”操作的访问权限/about。由于默认模式路由仍然存在,因此我们也可以使用常规/home/about路由访问“关于”页面。
3.使用属性
您还可以使用控制器中的属性和操作来配置路由。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[Route("[controller]")] public class AnalyticsController : Controller { [Route("Dashboard")] public IActionResult Index() { return View(); } [Route("[action]")] public IActionResult Charts() { return View(); } } |
在本示例中,我们可以通过以下路径访问控制器操作:
/Analytics/Dashboard
/Analytics/Charts
您可以看到这两个标记,[controller]并[action]指出我们必须引用已声明的控制器和操作名称。在这种情况下,“Analytics”是控制器的名称,“Charts”是动作的名称,因此它是路由的名称。
4.构建RESTful路线
为了声明一个RESTful控制器,我们需要使用以下路由配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[Route("api/[controller]")] public class ValuesController : Controller { // GET api/values [HttpGet] public IEnumerable<string> Get() { return new string[] {"hello", "world!"}; } // POST api/values [HttpPost] public void PostCreate([FromBody] string value) { } } |
在这里,我们告诉我们的RESTful服务接受/api/values路由下的呼叫。请注意,我们不再使用该Route属性进行操作。相反,我们与装饰它HttpGet,HttpPost,HttpPut,HttpDelete的属性。
或者,我们可以看看不同的场景:
1 2 3 4 5 6 |
// POST api/values/5 [HttpPost("{id}")] public void PostUpdate(int id, [FromBody] string value) { } |
在这里,我们有以下路线的控制器值
HTTP Post的/values路线将调用Post()行动
HTTP Post的/values/PostName路线将调用Post([FromBody]string value)行动
5.使用约束
我们可以将使用约束传递给动作的值的类型进行限制。例如,如果我们期望一个参数是一个数字,我们必须将其限制为整数类型。使用大括号在属性中声明约束{id:int}。
1 2 3 4 5 6 |
[HttpGet("{id:int}")] public string GetById(int id) { return "item " + id; } |
在这里,我们告诉动作GetByID只接受一个整数参数。向约束添加问号{id:int?}表示该参数是可选的。因此,如果有问号,我们可以打电话/GetByID/123或/GetByID不带附加参数。我们也可以这样定义在Startup类中声明的默认路由中的约束:
1 2 3 4 5 |
routes.MapRoute( name: "getProductById", template: "Products/{id:int}", defaults: new { controller = "Products", action = "GetById" }); |
有几个可用的约束,如布尔,日期时间,小数,最小值,最大值,正则表达式等。