REST
表述性状态转移(Representational State Transfer,REST),不是一种标准,而是一种软件架构风格。
基于REST的服务与基于SOAP的服务相比,性能、效率和易用性上都更高,而SOAP协议非常的复杂和不透明。REST受到越来越多的Web服务供应商欢迎。
REST的主要原则是:
1.网络上的所有事物都可被抽象为资源;
2.每个资源都有一个唯一的资源标识符URI;
3.使用标准方法操作资源;
4.所有的操作都是无状态的;
5.通过缓存来提高性能。
REST是基于Http协议的,任何对资源的操作行为都是通过Http协议来实现。Http把对一个资源的操作限制在4个方法以内:GET、POST、PUT和DELETE,这正是对资源CRUD操作的实现。
REST的资源表述形式可以是XML、HTML、JSON,或者其他任意的形式,这取决于服务提供商和消费服务的用户。
但是REST不是万能的。操作无状态也会带来巨大的安全问题,如何授权和验证用户?如果要求每次请求都包含完整的身份和验证信息,又如何避免信息泄漏?复杂的功能挑战架构的易用性,这就需要在性能与功能间权衡,究竟该用REST还是SOAP。
WebHttpBinding
WebHttpBinding允许开发人员通过 HTTP请求(这些请求使用“Plain old XML”(POX) 样式消息,而不是使用基于 SOAP 的消息)来公开 Web 服务,可以很便利的实现REST。与其他绑定不同的是:必须使用WebHttpBehavior对服务的终结点进行配置。还要求使用WebGetAttribute或WebInvokeAttribute属性将各个服务操作映射到URI,同时定义调用和返回结果的消息格式。
服务契约
先定义服务契约。这里提供两个方法,分别采用GET和POST方式访问。
我们可以看到,与普通WCF服务契约不同的是,需要额外用WebGet或者WebInvoke指定REST访问的方式。另外还要指定消息包装样式和消息格式,默认的消息请求和响应格式为XML,若选择JSON需要显式声明。
UriTemplate用来将方法映射到具体的Uri上,但如果不指定映射,将映射到默认的Uri。比如采用Get访问的GetUser方法,默认映射是:/GetUser?Name={Name}&Position={Position}。
IContract
namespace Rest.Contract
{
[DataContractFormat]
[ServiceContract]
public interface ITest
{
//[WebGet(UriTemplate = "/User/Get/{Name}/{Position}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
[WebGet(UriTemplate = "/User/Get/{Name}/{Position}", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
List<User> GetUser(string Name, string Position);
//[WebInvoke(Method = "POST", UriTemplate = "/User/Create", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
[WebInvoke(Method = "POST", UriTemplate = "/User/Create", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
Result CreateUser(User u);
}
[DataContract(Namespace = "http://rest-server/datacontract/user")]
public class User
{
[DataMember]
public long ID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public int Sex { get; set; }
[DataMember]
public string Position { get; set; }
[DataMember]
public string Email { get; set; }
}
[DataContract(Namespace = "http://rest-server/datacontract/result")]
public class Result
{
[DataMember]
public string Value { get; set; }
}
}
服务端
这里最简单的实现GetUser和CreateUser两个方法的逻辑,关注点不在这里。
Service类
namespace Rest.Service
{
public class Test : ITest
{
/// <summary>
/// GET
/// </summary>
/// <param name="Name"></param>
/// <param name="Position"></param>
/// <returns></returns>
public List<User> GetUser(string Name, string Position)
{
List<User> userList = List.Where(u => u.Name == Name && u.Position == Position).ToList();
return userList;
}
/// <summary>
/// POST
/// </summary>
/// <param name="u"></param>
/// <returns></returns>
public Result CreateUser(User u)
{
Result result = new Result();
if (!List.Any(user => user.ID == u.ID))
List.Add(u);
result.Value = u.ID.ToString();
return result;
}
/// <summary>
/// 测试数据
/// </summary>
private static List<User> List
{
get
{
List<User> list = new List<User>{
new User{
ID = 19735,
Name = "wuhong",
Sex = 1,
Position = "engineer",
Email = "star_2345@qq.com"
}
};
return list;
}
}
}
}
服务端的配置文件中只有一个特别处,必须使用WebHttpBehavior对服务的终结点进行配置。
Web.Config
<system.serviceModel> <bindings> <webHttpBinding> <binding name="webBinding"> </binding> </webHttpBinding> </bindings> <services> <service name="Rest.Service.Test" behaviorConfiguration="testServiceBehavior"> <endpoint address="" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="webBinding" contract="Wuhong.Rest.Contract.ITest"> </endpoint> </service> </services> <behaviors> <endpointBehaviors> <behavior name="webBehavior"> <!--这里必须设置--> <webHttp /> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior name="testServiceBehavior"> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
客户端
为了强调REST的通用性,客户端不用WCF的形式调用服务,而是用另外两种通用的方式:
一是用C#编程直接HTTP访问,消息格式我们选XML;
二是用jquery实现GET和POST访问,消息格式我们选JSON。
先实现C#方式,我们封装一个Client类,实现HTTP的GET和POST方式。

namespace Rest.Client
{
public class RestClient
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="baseUrl"></param>
public RestClient(string baseUri)
{
his.BaseUri = baseUri;
}
/// <summary>
/// 基地址
/// </summary>
private string BaseUri;
/// <summary>
/// Post调用
/// </summary>
/// <param name="data"></param>
/// <param name="uri"></param>
/// <returns></returns>
public string Post(string data, string uri)
{
//Web访问对象
string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri);
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
//转成网络流
byte[] buf = UnicodeEncoding.UTF8.GetBytes(data);
//设置
myRequest.Method = "POST";
myRequest.ContentLength = buf.Length;
myRequest.ContentType = "text/html";
// 发送请求
Stream newStream = myRequest.GetRequestStream();
newStream.Write(buf, 0, buf.Length);
newStream.Close();
// 获得接口返回值
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
string ReturnXml = HttpUtility.HtmlDecode(reader.ReadToEnd());
reader.Close();
myResponse.Close();
return ReturnXml;
}
/// <summary>
/// Get调用
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public string Get(string uri)
{
//Web访问对象
string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri);
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
// 获得接口返回值
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
string ReturnXml = HttpUtility.UrlDecode(reader.ReadToEnd());
reader.Close();
myResponse.Close();
return ReturnXml;
}
}
}
下面是主函数,按顺序调用两个接口,并显示返回值。需要注意XML约定的命名空间:

namespace Rest.Client
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 //初始化
8 RestClient client = new RestClient(ClientConfiguration.ServiceUrl);
9
10 //Get
11 string uriGet = string.Format("User/Get/{0}/{1}", "wuhong", "engineer");
12 string retGet = client.Get(uriGet);
13
14 Console.WriteLine(retGet);
15
16 //Post
17 string uriPost = "User/Create";
18 string data = "<User xmlns=\"http://rest-server/datacontract/user\"><ID>19735</ID><Name>wuhong</Name><Sex>1</Sex><Position>engineer</Position><Email>star_2345@qq.com</Email></User>";
19
20 string retPost = client.Post(data, uriPost);
21
22 Console.WriteLine(retPost);
23
24 Console.ReadLine();
25 }
26 }
27
28 }
29
接下来实现javascript方式。
这里采用jquery访问REST服务,为了javascript操作数据的便利,消息格式选择JSON,可以忽略数据契约的命名空间。不过需要服务契约做一点修改,显式指定请求或响应消息的格式,例如:
1 [WebInvoke(Method = "POST", UriTemplate = "User/Create", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
Html代码:

<html>
<head>
<script src="jquery-1.3.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
function HttpGet() {
$.get( http://doxt-wuhong/Wuhong.Rest.Web/TestService.svc/User/Get/wuhong/engineer ,
function(data) {
$("#TextGet").val(data);
});
}
function HttpPost() {
var str = "{ \"Email\": \"star_2345@qq.com\", \"ID\": 19735, \"Name\": \"wuhong\", \"Position\": \"engineer\", \"Sex\": 1 }";
$.ajax({
type: "POST",
contentType: "application/json",
url: http://doxt-wuhong/Wuhong.Rest.Web/TestService.svc/User/Create,
data: str,
success: function(data) {
$("#TextPost").val(data);
}
});
}
</script>
<style type="text/css">
#TextGet
{
width: 700px;
}
#TextPost
{
width: 700px;
}
</style>
</head>
<body>
<input id="ButtonGet" type="button" value="GET" onclick="HttpGet()" />
<input id="TextGet" type="text" />
<p/>
<input id="ButtonPost" type="button" value="POST" onclick="HttpPost()" />
<input id="TextPost" type="text" />
</body>
</html>
来源:https://www.cnblogs.com/fer-team/p/7919233.html
