restful 订阅
RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务使能接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源。 [1] 展开全文
RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务使能接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源。 [1]
信息
创始人
Roy Fielding
外文名
Representational State Transfer
应用场景
适用于移动互联网厂商作为业务使能接口的场景
所属领域
计算机科学技术
中文名
RESTful
实    质
一种网络应用程序的设计风格和开发方式
RESTful相关定义
REST(英文:Representational State Transfer,简称 REST)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,Roy Fielding是 HTTP 规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,无论是对URL的处理还是对Payload的编码,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。 [2]  REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。Web 应用程序最重要的 REST 原则是,客户端和服务器之间的交互在请求之间是无状态的。从客户端到服务器的每个请求都必须包含理解请求所必需的信息。如果服务器在请求之间的任何时间点重启,客户端不会得到通知。此外,无状态请求可以由任何可用服务器回答,这十分适合云计算之类的环境。客户端可以缓存数据以改进性能。在服务器端,应用程序状态和功能可以分为各种资源。资源是一个有趣的概念实体,它向客户端公开。资源的例子有:应用程序对象、数据库记录、算法等等。每个资源都使用 URI (Universal Resource Identifier) 得到一个唯一的地址。所有资源都共享统一的接口,以便在客户端和服务器之间传输状态。使用的是标准的 HTTP 方法,比如 GET、PUT、POST 和 DELETE。Hypermedia 是应用程序状态的引擎,资源表示通过超链接互联。
收起全文
精华内容
参与话题
问答
  • restful 简单理解

    万次阅读 多人点赞 2016-11-26 09:15:12
    越来越多的人开始意识到,网站即软件,而且是一种新型的软件。 这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点。 ...

    越来越多的人开始意识到,网站即软件,而且是一种新型的软件。

    这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点。

    网站开发,完全可以采用软件开发的模式。但是传统上,软件和网络是两个不同的领域,很少有交集;软件开发主要针对单机环境,网络则主要研究系统之间的通信。互联网的兴起,使得这两个领域开始融合,现在我们必须考虑,如何开发在互联网环境中使用的软件。

    图片2.jpg

    RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

     

    但是,到底什么是RESTful架构,并不是一个容易说清楚的问题。

      REST究竟是什么?因为REST的内涵非常丰富,所以很难用一两句话解释清楚这个问题。

    下面,我就谈谈我理解的RESTful架构。

    一、起源

        REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。


     Fielding将他对互联网软件的架构原则,定名为 REST,即Representational State Transfer的缩写。我对这个词组的翻译是"表现层状态转化"。


    如果一个架构符合REST原则,就称它为RESTful架构。


    图片1.jpg

    Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了关注,并且立即对互联网开发产生了深远的影响。

    他这样介绍论文的写作目的:

    "本文研究计算机科学两大前沿----软件和网络----的交叉点。长期以来,软件研究主要关注软件设计的分类、设计方法的演化,很少客观地评估不同的设计选择对系统行为的影响。而相反地,网络研究主要关注系统之间通信行为的细节、如何改进特定通信机制的表现,常常忽视了一个事实,那就是改变应用程序的互动风格比改变互动协议,对整体表现有更大的影响。我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。"

    二、名称

    要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把这个名称搞懂了,也就不难体会REST是一种什么样的设计。

    三、资源(Resources)

    REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。

    所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

    所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI。

    四、表现层(Representation)

    "资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

    比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

    URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。

    五、状态转化(State Transfer)

    访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

    互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

    客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

    六、综述

    综合上面的解释,我们总结一下什么是RESTful架构:

      (1)每一个URI代表一种资源;

      (2)客户端和服务器之间,传递这种资源的某种表现层;

      (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

    七、 举个例子:

        Marcus是一个农民,他有4头猪,12只鸡和3头奶牛。他现在模拟一个REST API,而我是客户端。如果我想用REST来请求当前的农场状态,我仅会问:“State”Marcus会回答:“4头猪、12只鸡、3头奶牛


        这是REST最简单的一个例子。Marcus使用表征来传输农场状态。表征的句子很简单:“4头猪、12只鸡、3头奶牛


        再往下看,看我如何让MarcusREST方式添加2头奶牛?


        按照常理,可以会这样说Marcus,请在农场你再添加2头奶牛。难道这就是REST方式吗?难道就是通过这样的表征来传输状态的吗?不是的!这是一个远程过程调用,过程是给农场添加2头奶牛。


        Marcus很愤怒地响应到:“400Bad Request”,你到底是什么意思?


        所以,让我们重新来一次。我们怎样做到REST方式呢?该怎样重新表征呢?它应该是4头猪、12只鸡、3头奶牛。好,让我们再次重新表征……


        我:“Marcus……4头猪、12只鸡、5奶牛!

        Marcus好的

        我:“Marcus,现在是什么状态?

        Marcus“4头猪、12只鸡、5头奶牛

        我:好!


        看到了吗?就这样简单。

    restful就是满足以下约束

    使用客户/服务器模型。

         客户和服务器之间通过一个统一的接口来互相通讯。

     

     层次化的系统。

        在一个REST系统中,客户端并不会固定地与一个服务器打交道。

     

     无状态。

        在一个REST系统中,服务端并不会保存有关客户的任何状态。也就是说,客户端自身负责用户状态的维持,并在每次发送请求时都需要提供足够的信息。


    可缓存。

        REST系统需要能够恰当地缓存请求,以尽量减少服务端和客户端之间的信息传输,以提高性能。

     

    统一的接口。

        一个REST系统需要使用一个统一的接口来完成子系统之间以及服务与用户之间的交互。这使得REST系统中的各个子系统可以独自完成演化。


    如果一个系统满足了上面所列出的五条约束,那么该系统就被称为是RESTful的。

    、误区

    RESTful架构有一些典型的设计误区。

    最常见的一种设计错误,就是URI包含动词。因为"资源"表示一种实体,所以应该是名词,URI不应该有动词,动词应该放在HTTP协议中。

    举例来说,某个URI是/posts/show/1,其中show是动词,这个URI就设计错了,正确的写法应该是/posts/1,然后用GET方法表示show。

    如果某些动作是HTTP动词表示不了的,你就应该把动作做成一种资源。比如网上汇款,从账户1向账户2汇款500元,错误的URI是:

      POST /accounts/1/transfer/500/to/2

    正确的写法是把动词transfer改成名词transaction,资源不能是动词,但是可以是一种服务:

      POST /transaction HTTP/1.1
      Host: 127.0.0.1
      
      from=1&to=2&amount=500.00

    另一个设计误区,就是在URI中加入版本号

      http://www.example.com/app/1.0/foo

      http://www.example.com/app/1.1/foo

      http://www.example.com/app/2.0/foo

    因为不同的版本,可以理解成同一种资源的不同表现形式,所以应该采用同一个URI。版本号可以在HTTP请求头信息的Accept字段中进行区分(参见Versioning REST Services):

      Accept: vnd.example-com.foo+json; version=1.0

      Accept: vnd.example-com.foo+json; version=1.1

      Accept: vnd.example-com.foo+json; version=2.0

    (完)


    展开全文
  • 面试官:你连RESTful都不知道我怎么敢要你?

    万次阅读 多人点赞 2019-11-06 00:33:54
    干货,2019 RESTful最贱实践

    效率工具前文传送门

    01 前言

    回归正题,看过很多RESTful相关的文章总结,参齐不齐,结合工作中的使用,非常有必要归纳一下关于RESTful架构方式了,RESTful只是一种架构方式的约束,给出一种约定的标准,完全严格遵守RESTful标准并不是很多,也没有必要。但是在实际运用中,有RESTful标准可以参考,是十分有必要的。

    实际上在工作中对api接口规范、命名规则、返回值、授权验证等进行一定的约束,一般的项目api只要易测试、足够安全、风格一致可读性强、没有歧义调用方便我觉得已经足够了,接口是给开发人员看的,也不是给普通用户去调用。

    02 RESTful的来源

    REST:Representational State Transfer(表象层状态转变),如果没听说过REST,你一定以为是rest这个单词,刚开始我也是这样认为的,后来发现是这三个单词的缩写,即使知道了这三个单词理解起来仍然非常晦涩难懂。如何理解RESTful架构,最好的办法就是深刻理解消化Representational State Transfer这三个单词到底意味着什么。

    1.每一个URI代表一种资源;

    2.客户端和服务器之间,传递这种资源的某种表现层;

    3.客户端通过四个HTTP动词(get、post、put、delete),对服务器端资源进行操作,实现”表现层状态转化”。

    是由美国计算机科学家Roy Fielding(百度百科没有介绍,真是尴尬了)。Adobe首席科学家、Http协议的首要作者之一、Apache项目联合创始人。

    03 RESTful6大原则

    REST之父Roy Fielding在论文中阐述REST架构的6大原则。

    1. C-S架构

    数据的存储在Server端,Client端只需使用就行。两端彻底分离的好处使client端代码的可移植性变强,Server端的拓展性变强。两端单独开发,互不干扰。

    2. 无状态

    http请求本身就是无状态的,基于C-S架构,客户端的每一次请求带有充分的信息能够让服务端识别。请求所需的一些信息都包含在URL的查询参数、header、body,服务端能够根据请求的各种参数,无需保存客户端的状态,将响应正确返回给客户端。无状态的特征大大提高的服务端的健壮性和可拓展性。

    当然这总无状态性的约束也是有缺点的,客户端的每一次请求都必须带上相同重复的信息确定自己的身份和状态(这也是必须的),造成传输数据的冗余性,但这种确定对于性能和使用来说,几乎是忽略不计的。

    3.统一的接口

    这个才是REST架构的核心,统一的接口对于RESTful服务非常重要。客户端只需要关注实现接口就可以,接口的可读性加强,使用人员方便调用。

    4.一致的数据格式

    服务端返回的数据格式要么是XML,要么是Json(获取数据),或者直接返回状态码,有兴趣的可以看看博客园的开放平台的操作数据的api,post、put、patch都是返回的一个状态码 。

    自我描述的信息,每项数据应该是可以自我描述的,方便代码去处理和解析其中的内容。比如通过HTTP返回的数据里面有 [MIME type ]信息,我们从MIME type里面可以知道数据的具体格式,是图片,视频还是JSON,客户端通过body内容、查询串参数、请求头和URI(资源名称)来传送状态。服务端通过body内容,响应码和响应头传送状态给客户端。这项技术被称为超媒体(或超文本链接)。

    除了上述内容外,HATEOS也意味着,必要的时候链接也可被包含在返回的body(或头部)中,以提供URI来检索对象本身或关联对象。下文将对此进行更详细的阐述。

    如请求一条微博信息,服务端响应信息应该包含这条微博相关的其他URL,客户端可以进一步利用这些URL发起请求获取感兴趣的信息,再如分页可以从第一页的返回数据中获取下一页的URT也是基于这个原理。

    4.系统分层

    客户端通常无法表明自己是直接还是间接与端服务器进行连接,分层时同样要考虑安全策略。

    5.可缓存

    在万维网上,客户端可以缓存页面的响应内容。因此响应都应隐式或显式的定义为可缓存的,若不可缓存则要避免客户端在多次请求后用旧数据或脏数据来响应。管理得当的缓存会部分地或完全地除去客户端和服务端之间的交互,进一步改善性能和延展性。

    6.按需编码、可定制代码(可选)

    服务端可选择临时给客户端下发一些功能代码让客户端来执行,从而定制和扩展客户端的某些功能。比如服务端可以返回一些 Javascript 代码让客户端执行,去实现某些特定的功能。
    提示:REST架构中的设计准则中,只有按需编码为可选项。如果某个服务违反了其他任意一项准则,严格意思上不能称之为RESTful风格。

    03 RESTful的7个最佳实践

    1. 版本

    如github开放平台
    https://developer.github.com/v3/

    就是将版本放在url,简洁明了,这个只有用了才知道,一般的项目加版本v1,v2,v3?好吧,这个加版本估计只有大公司大项目才会去使用,说出来不怕尴尬,我真没用过。有的会将版本号放在header里面,但是不如url直接了当。

    https://example.com/api/v1/
    

    2.参数命名规范

    query parameter可以采用驼峰命名法,也可以采用下划线命名的方式,推荐采用下划线命名的方式,据说后者比前者的识别度要高,可能是用的人多了吧,因人而异,因团队规范而异吧。

    https://example.com/api/users/today_login 获取今天登陆的用户 
    https://example.com/api/users/today_login&sort=login_desc 获取今天登陆的用户、登陆时间降序排列
    

    3.url命名规范

    API 命名应该采用约定俗成的方式,保持简洁明了。在RESTful架构中,每个url代表一种资源所以url中不能有动词,只能有名词,并且名词中也应该使用复数。实现者应使用相应的Http动词GET、POST、PUT、PATCH、DELETE、HEAD来操作这些资源即可

    不规范的的url,冗余没有意义,形式不固定,不同的开发者还需要了解文档才能调用。

    https://example.com/api/getallUsers GET 获取所有用户 
    https://example.com/api/getuser/1 GET 获取标识为1用户信息 
    https://example.com/api/user/delete/1 GET/POST 删除标识为1用户信息 
    https://example.com/api/updateUser/1 POST 更新标识为1用户信息 
    https://example.com/api/User/add POST 添加新的用户
    

    规范后的RESTful风格的url,形式固定,可读性强,根据users名词和http动词就可以操作这些资源

    https://example.com/api/users GET 获取所有用户信息 
    https://example.com/api/users/1 GET 获取标识为1用户信息 
    https://example.com/api/users/1 DELETE 删除标识为1用户信息 
    https://example.com/api/users/1 Patch 更新标识为1用户部分信息,包含在body中 
    https://example.com/api/users POST 添加新的用户
    

    4. 统一返回数据格式

    对于合法的请求应该统一返回数据格式,这里演示的是json

    • code——包含一个整数类型的HTTP响应状态码。
    • status——包含文本:”success”,”fail”或”error”。HTTP状态响应码在500-599之间为”fail”,在400-499之间为”error”,其它均为”success”(例如:响应状态码为1XX、2XX和3XX)。这个根据实际情况其实是可要可不要的。
    • message——当状态值为”fail”和”error”时有效,用于显示错误信息。参照国际化(il8n)标准,它可以包含信息号或者编码,可以只包含其中一个,或者同时包含并用分隔符隔开。
    • data——包含响应的body。当状态值为”fail”或”error”时,data仅包含错误原因或异常名称、或者null也是可以的

    返回成功的响应json格式

    {
      "code": 200,
      "message": "success",
      "data": {
        "userName": "123456",
        "age": 16,
        "address": "beijing"
      }
    }
    

    返回失败的响应json格式

    {
      "code": 401,
      "message": "error  message",
      "data": null
    }
    

    下面这个ApiResult的泛型类是在项目中用到的,拓展性强,使用方便。返回值使用统一的 ApiResult 或 ApiResult
    错误返回 使用 ApiResult.Error 进行返回; 成功返回,要求使用 ApiResult.Ok 进行返回

    public class ApiResult: ApiResult
        {
            public new static ApiResult<T> Error(string message)
            {
                return new ApiResult<T>
                {
                    Code = 1,
                    Message = message,
                };
            }
            [JsonProperty("data")]
            public T Data { get; set; }
        }
        public class ApiResult
        {
            public static ApiResult Error(string message)
            {
                return new ApiResult
                {
                    Code = 1,
                    Message = message,
                };
            }
    
            public static ApiResult<T> Ok<T>(T data)
            {
                return new ApiResult<T>()
                {
                    Code = 0,
                    Message = "",
                    Data = data
                };
            }
            /// <summary>
            /// 0 是 正常 1 是有错误
            /// </summary>
            [JsonProperty("code")]
            public int Code { get; set; }
            [JsonProperty("msg")]
            public string Message { get; set; }
    
            [JsonIgnore]
            public bool IsSuccess => Code == 0;
        }
    

    5. http状态码

    在之前开发的xamarin android博客园客户端的时候,patch、delete、post操作时body响应里面没有任何信息,仅仅只有http status code。HTTP状态码本身就有足够的含义,根据http status code就可以知道删除、添加、修改等是否成功。(ps:有点linux设计的味道哦,没有返回消息就是最好的消息,表示已经成功了)服务段向用户返回这些状态码并不是一个强制性的约束。简单点说你可以指定这些状态,但是不是强制的。常用HTTP状态码对照表
    HTTP状态码也是有规律的

    • 1**请求未成功
    • 2**请求成功、表示成功处理了请求的状态代码。
    • 3**请求被重定向、表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
    • 4** 请求错误这些状态代码表示请求可能出错,妨碍了服务器的处理。
    • 5**(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

    6. 合理使用query parameter

    在请求数据时,客户端经常会对数据进行过滤和分页等要求,而这些参数推荐采用HTTP Query Parameter的方式实现

    比如设计一个最近登陆的所有用户
    https://example.com/api/users?recently_login_day=3
    
    搜索用户,并按照注册时间降序
    https://example.com/api/users?recently_login_day=3
    
    搜索用户,并按照注册时间升序、活跃度降序
    https://example.com/api/users?q=key&sort=create_title_asc,liveness_desc
    
    关于分页,看看博客园开放平台分页获取精华区博文列表
    https://api.cnblogs.com/api/blogposts/@picked?pageIndex={pageIndex}&pageSize={pageSize} 
    返回示例: 
    [ 
    { 
    “Id”: 1, 
    “Title”: “sample string 2, 
    “Url”: “sample string 3, 
    “Description”: “sample string 4, 
    “Author”: “sample string 5, 
    “BlogApp”: “sample string 6, 
    “Avatar”: “sample string 7, 
    “PostDate”:2017-06-25T20:13:38.892135+08:00, 
    “ViewCount”: 9, 
    “CommentCount”: 10, 
    “DiggCount”: 11 
    }, 
    { 
    “Id”: 1, 
    “Title”: “sample string 2, 
    “Url”: “sample string 3, 
    “Description”: “sample string 4, 
    “Author”: “sample string 5, 
    “BlogApp”: “sample string 6, 
    “Avatar”: “sample string 7, 
    “PostDate”:2017-06-25T20:13:38.892135+08:00, 
    “ViewCount”: 9, 
    “CommentCount”: 10, 
    “DiggCount”: 11 
    } 
    ]
    

    7. 多表、多参数连接查询如何设计URL

    这是一个比较头痛的问题,在做单个实体的查询比较容易和规范操作,但是在实际的API并不是这么简单而已,这其中常常会设计到多表连接、多条件筛选、排序等。
    比如我想查询一个获取在6月份的订单中大于500元的且用户地址是北京,用户年龄在22岁到40岁、购买金额降序排列的订单列表

    https://example.com/api/orders?order_month=6&order_amount_greater=500&address_city=北京&sort=order_amount_desc&age_min=22&age_max=40
    

    从这个URL上看,参数众多、调用起来还得一个一个仔细对着,而且API本身非常不容易维护,命名看起来不是很容易,不能太长,也不能太随意。

    在.net WebAPI总我们可以使用属性路由,属性路由就是讲路由附加到特定的控制器或操作方法上装饰Controll及其使用[Route]属性定义路由的方法称为属性路由。

    这种好处就是可以精准地控制URL,而不是基于约定的路由,简直就是为这种多表查询量身定制似的的。 从webapi 2开发,现在是RESTful API开发中最推荐的路由类型。
    我们可以在Controll中标记Route

    [Route(“api/orders/{address}/{month})] 
    

    Action中的查询参数就只有金额、排序、年龄。减少了查询参数、API的可读性和可维护行增强了。

    https://example.com/api/orders/beijing/6?order_amount_greater=500&sort=order_amount_desc&age_min=22&age_max=40
    

    这种属性路由比如在博客园开放的API也有这方面的应用,如获取个人博客随笔列表

    请求方式:GET 
    请求地址:https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex} 
    (ps:blogApp:博客名)
    

    作者信息:
    【文章信息】:
    作者-张林
    原文链接-https://blog.csdn.net/kebi007/article/details/102927209
    【原创公众号】:dotNet全栈开发。
    【简介】:CSDN 博客专家, xamarin跨平台开发者,博客园app开发者(ps:虽然下载量还行10万+,并没有什么大用)这是一个坚持原创的技术公众号,每天坚持推送各种 dotNet 基础/进阶文章,编程技巧,爬虫实战,面试经验,xamarin开发系列不定期分享各类资源。
    【福利】:送你新人大礼包一份,关注微信公众号,后台回复:“CSDN” 即可获取!
    版权声明:本文为CSDN博主「dotNet全栈开发」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    ————————————————
    版权声明:本文为CSDN博主「dotnet全栈开发」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/kebi007/article/details/103655685

    展开全文
  • REST,以及RESTful的讲解

    千次阅读 2019-03-26 15:51:46
    1.传统下的API接口 http是目前在互联网上使用最多... ...  如果说你要删除一个数据,以往的做法通常是 delete/{id}   如果你要更新一个数据,可能是Post数据放Body,然后方法是 update/{id}, 或者是artichle/{id}...

    1.传统下的API接口

           http是目前在互联网上使用最多的协议,没有之一。 
      可是http的创始人一直都觉得,在过去10几年来,所有的人都在错误的使用Http.这句话怎么说呢? 
      如果说你要删除一个数据,以往的做法通常是 delete/{id}  
      如果你要更新一个数据,可能是Post数据放Body,然后方法是 update/{id}, 或者是artichle/{id}?method=update  
      这种做法让Roy Fielding很暴燥,他觉得这个世界不该这样的,所有的人都在误解而且在严重错误的误解Http的设计初衷,好比是发明了火药却只用它来做烟花爆竹。 
      那么正确的使用方式是什么呢?如果你要看Rest各种特性,你恐怕真的很难理解Rest,但是如果你看错误的使用http的人倒底儿了哪些错,什么是Rest就特别容易理解了。  
       
    七宗罪的第一条,混乱。  

      一万个人心里有一万个Url的命名规则,Url是统一资源定位符,重点是资源。而很多人却把它当成了万金油,每一个独立的虚拟的网页都可以随意使用,各种操作都能够迭加。这是混乱的来源之一。 
    比如:

    https://localhost:8080/myweb/getUserById?id=1
    https://localhost:8080/myweb/user/getById?id=1
    https://localhost:8080/myweb/x/y?id=1

    第二条,贪婪。

      有状态和无状态全部混在一起。特别是在购物车或者是登录的应用中,经常刷新就丢失带来的用户体验简直棒棒哒。每一个请求并不能单独的响应一些功能,很多的功能混杂在一起里。这是人性贪婪的本质,也是各种Hack的起源,只要能够把问题解决掉,总会有人用他认为最方便的方式去解决问题,比如说汽车门把手坏掉了直接系根绳子当把手,emmmm这样确实很棒啊。 
       
    第三条,无序。

      返回的结果往往是很随意,各种错误信息本来就是用Http的状态码构成的,可是很多人还是喜欢把错误信息返回在返回值中。最常见的就是Code和Message,当然对于这一点,我个人是保留疑问的,我的观点是,Http本身的错误和服务器的内部错误还是需要在不断层面分开的,不能混在一起。可是在大神眼里并非如此。

    那么怎么解决这些问题呢? 

           强迫症患者的福音就是先颁规则,第一个规则就是明确Url是什么,该怎么用。就是所有的Url本质来讲,都应该是一种资源。一个独立的Url地址,就是对应一个独一无二的资源。怎么样?这种感觉是不是棒棒哒?一个冰淇淋,一个老师,一间房子,在Url上对应的都是一个资源,不会有多余的Url跟他对应,也不会表示有多个Url地址。
      注意,这里点的是Url地址,并不是单独的参数,他就是一个/room/{room_id}这样的东西,举个栗子,/room/3242 这就表示3242号房间。这是一个清爽的世界啊,你想想,之前的Url是什么都要,我开房,可能是/open/room/3242 我要退房可能是/exit/3242/room,我要打理房间,可能是room/3242?method=clean.够了!这些乱七八糟的东西全够了,让世界回归清爽的本质,一间房,就是/room/3242 没有别的Url地址了。 
      在过去的混乱世界里,经常用的就是Get和Post。如果不是因为Get不支持大数据传输,我想连Post都不会有人使用。(想像一下Roy Fielding在愤怒的对着电脑屏幕喊,Http的Method一共有八个,你们为毛只逮着Get一只羊的毛薅薅薅薅薅)。

      而对资源最常见的操作是什么?CRUD,对不对,就是创建,读,更新,删除。再看Http的Method?是不是非常完美?其实也怪Fielding老爷子一开始命名不准确,如果刚开始就是把Get方法叫做Read,Put方法叫做Update,Post叫做Create这该多好。。。 
      你用一个Get,大家又发现没什么限制没什么所谓,又很难理解Put和Post的差别,法无禁止即可为啊,呃,老爷子不要瞪我,我瞎说的。总之,这四种方法够不够你浪?你有本身找出来更多的对资源的操作来啊,我还有4个Method没用过呢。如果这4个真的不够了,有什么问题,大不了我再重新更改http协议啊。其实简单说,对于Rest理解到这里就够了。后续的东西,都是在这一条基础上空想出来的,比强迫症更强迫症,当然,无状态我是百分百支持的。以上的各种表述可能不太准确,也纯属是我的意淫和各种小道资料,并未考据,但是凭良心讲,我是早就看不惯黑暗年代里的Url命名风格了,所以当时最早接触到Rest的时候,瞬间就找到了真爱,我靠,这不就是我一直想要的答案吗?但是我一直想的仅仅是命名规范,从来没有把自己的思考角度放在一个url就是一个资源,所有的操作都是对资源的更改而言的角度上啊。所以你能理解到的程度,更多的就是在于你要弄清楚你要解决的什么问题,如果你的问题只是理解Rest,恐怕你很理解,如果你的问题是怎么解决Url混乱的问题,你反而很快能弄懂了~

    对比

    https://localhost:8080/myweb/getDogs --> GET /rest/api/dogs 获取所有小狗狗 
    https://localhost:8080/myweb/addDogs --> POST /rest/api/dogs 添加一个小狗狗 
    https://localhost:8080/myweb/updateDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一个小狗狗 
    https://localhost:8080/myweb/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 删除一个小狗狗

    左边是我们写的,而且后台我们可能会写出很多返回值,而且各种各样的,比如 

    https://localhost:8080/myweb/addDogs

    操作成功 或者 1
    或者

    操作失败 或者 0
    这还要我们自己去解析,还要前端和后端去协商你返回的0是啥意识啊。但是REST返回值是标准的,比如

    HTTP/1.1 200 OK
    Content-Type: application/json
    Content-Length: xxx
    
    {
       "url" : "/api/categories/1",
       "label" : "Food",
       "items_url" : "/api/items?category=1",
       "brands" : [
             {
                "label" : "友臣",
                "brand_key" : "32073",
                "url" : "/api/brands/32073"
             }, {
                "label" : "乐事",
                "brand_key" : "56632",
                "url" : "/api/brands/56632"
             }
             ...
       ]
    }

           格式固定,第一行永远是操作失败或者成功的状态码,第二行是返回的类型,第三行内容的长度,第五行开始是内容。

    这样我只需写一个程序解析返回的信息就可以了,可以重用,但是我们上面传统的不仅仅要协商,还有有不同的解析程序,稍微改变,就不能正常使用了。所以rest的明显更加通用。

    例子2

    1、获取文章

    请求:

    GET /blog/post/{postId} HTTP/1.1

    响应:

    HTTP/1.1 200 OK
    {
        "title": "foobar",
        "content": "foobar",
        "comments": ["", "", ""]
    }

    2、发布文章

    请求:

    POST /blog/post HTTP/1.1
    {
        "title": "foobar",
        "content": "foobar",
        "comments": ["", "", ""]
    }

    响应:

    HTTP/1.1 201 CREATED

    规则

    GET    用来获取资源,
    POST  用来新建资源(也可以用于更新资源),
    PUT    用来更新资源,
    DELETE  用来删除资源

    例子

    DELETE http://api.qc.com/v1/friends: 删除某人的好友 (在http parameter指定好友id)
    POST http://api.qc.com/v1/friends: 添加好友UPDATE 
    http://api.qc.com/v1/profile: 更新个人资料

    概念

    REST 是面向资源的,这个概念非常重要,而资源是通过 URI 进行暴露。 
    URI 的设计只要负责把资源通过合理方式暴露出来就可以了。对资源的操作与它无关,操作是通过 HTTP动词来体现,所以REST 通过 URI 暴露资源时,会强调不要在 URI 中出现动词。

    比如:左边是错误的设计,而右边是正确的

    GET /rest/api/getDogs --> GET /rest/api/dogs 获取所有小狗狗 
    GET /rest/api/addDogs --> POST /rest/api/dogs 添加一个小狗狗 
    GET /rest/api/editDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一个小狗狗 
    GET /rest/api/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 删除一个小狗狗

           REST很好地利用了HTTP本身就有的一些特征,如HTTP动词、HTTP状态码、HTTP报头等等 。
           REST API 是基于 HTTP的,所以你的API应该去使用 HTTP的一些标准。这样所有的HTTP客户端(如浏览器)才能够直接理解你的API(当然还有其他好处,如利于缓存等等)。REST 实际上也非常强调应该利用好 HTTP本来就有的特征,而不是只把 HTTP当成一个传输层这么简单了。

    HTTP/1.1 200 OK
    Content-Type: application/json
    Content-Length: xxx
    
    {
       "url" : "/api/categories/1",
       "label" : "Food",
       "items_url" : "/api/items?category=1",
       "brands" : [
             {
                "label" : "友臣",
                "brand_key" : "32073",
                "url" : "/api/brands/32073"
             }, {
                "label" : "乐事",
                "brand_key" : "56632",
                "url" : "/api/brands/56632"
             }
             ...
       ]
    }

    看这个响应,包含了http里面的状态码等信息。还会有http的一些报头。

    Authorization 认证报头 
    Cache-Control 缓存报头 
    Cnotent-Type  消息体类型报头 
    ......


    REST 系统的特征

           1. 客户-服务器(Client-Server),提供服务的服务器和使用服务的客户需要被隔离对待。
           2. 无状态(Stateless),来自客户的每一个请求必须包含服务器处理该请求所需的所有信息。换句话说,服务器端不能存储来自某个客户的某个请求中的信息,并在该客户的其他请求中使用。
           3. 可缓存(Cachable),服务器必须让客户知道请求是否可以被缓存。(Ross:更详细解释请参考 理解本真的REST架构风格 以及 StackOverflow 的这个问题 中对缓存的解释。)
           4. 分层系统(Layered System),服务器和客户之间的通信必须被这样标准化:允许服务器和客户之间的中间层(Ross:代理,网关等)可以代替服务器对客户的请求进行回应,而且这些对客户来说不需要特别支持。
           5. 统一接口(Uniform Interface),客户和服务器之间通信的方法必须是统一化的。(Ross:GET,POST,PUT.DELETE, etc)
           6. 支持按需代码(Code-On-Demand,可选),服务器可以提供一些代码或者脚本(Ross:Javascrpt,flash,etc)并在客户的运行环境中执行。这条准则是这些准则中唯一不必必须满足的一条。(Ross:比如客户可以在客户端下载脚本生成密码访问服务器。)

    详细解释

    无状态(Stateless)

         所谓无状态的,即所有的资源,都可以通过URI定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而改变。有状态和无状态的区别,举个简单的例子说明一下。如查询员工的工资,如果查询工资是需要登录系统,进入查询工资的页面,执行相关操作后,获取工资的多少,则这种情况是有状态的,因为查询工资的每一步操作都依赖于前一步操作,只要前置操作不成功,后续操作就无法执行;如果输入一个url即可得到指定员工的工资,则这种情况是无状态的,因为获取工资不依赖于其他资源或状态,且这种情况下,员工工资是一个资源,由一个url与之对应,可以通过HTTP中的GET方法得到资源,这是典型的RESTful风格。

    è¿éåå¾çæè¿°

    è¿éåå¾çæè¿°

    统一接口(Uniform Interface)

      RESTful架构风格规定,数据的元操作,即CRUD(create, read, update和delete,即数据的增删查改)操作,分别对应于HTTP方法:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源,这样就统一了数据操作的接口,仅通过HTTP方法,就可以完成对数据的所有增删查改工作。

    即:

    GET(SELECT):从服务器取出资源(一项或多项)。
    POST(CREATE):在服务器新建一个资源。
    PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)。
    PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)。
    DELETE(DELETE):从服务器删除资源。


    演化

    https://zhuanlan.zhihu.com/p/30396391?group_id=937244108725641216

    优点&缺点

    优点是因为他对uri进行了限制,只用于定义资源。这样看起来比较容易理解。尤其是对简单的对象的增删改查,很好理解。

    缺点是因为这种限制,导致设计uri变得复杂了。尤其是复杂的关系,操作,资源集合,硬性套用rest原则设计非常困难。在rest基础上的HATEOAS,返回的json里增加了相应的关系和url。这也同样带来问题。好处是对简单的关系,的确可以通过url进一步处理。但对复杂的关系和操作,HATEOAS并不能胜任描述。反而在单纯的数据中增加了一堆垃圾信息。

    是什么?

    REST是一个标准,一种规范,遵循REST风格可以使开发的接口通用,便于调用者理解接口的作用。

    参考: 
    https://www.zhihu.com/question/28557115 
    https://blog.igevin.info/posts/restful-architecture-in-general/

    展开全文
  • RESTful

    千次阅读 2019-10-13 13:04:37
    一、RESTful RESTful,一种通用的前后台交互方式 RESTful一般是指这种格式: (1)使用HTTP POST(或GET)进行数据交互 (2)请求数据和应答数据均为JSON格式(或XML) 二、RESTful接口的实现 RESTful的前端...

    一、RESTful

    RESTful,一种通用的前后台交互方式

    RESTful一般是指这种格式:

    (1)使用HTTP POST(或GET)进行数据交互

    (2)请求数据和应答数据均为JSON格式(或XML)

    二、RESTful接口的实现

    RESTful的前端实现

    前端:在发送请求时,把请求转成JSON字符串

    $.ajax({
    				type:"POST",    /*请求类型-POST/GET*/
    				url:"AddStudent?mode=admin&token=12930289",   /*服务URI,用相对地址*/
    				data:jsonStr,          /*附加请求参数*/
    				dataType:"json",   /*期望服务器返回的数据类型*/
    				success: function(resp)  /*已经将服务器返回的数据转成JS 对象*/
    				{
    					if(resp.error==0)
    					alert("提交成功");
    					else
    					alert("出错:"+resp.reason);
    				},
    				error: function(jqXHR, textstatus, errorThrown)
    				{
    					alert("错误:" +jqXHR.status);
    				}
    			});	

    后端:手工读取请求数据,转成JSONObject,然后再做处理

    //读取请求数据,转化为字符串
    String reqText = readAsText(request.getInputStream(), "utf-8");
    		
    //转化为json
    JSONObject jreq = new JSONObject(reqText);

    三、RESTful附加URL参数

    一般来说,使用RESTful接口时,所有的请求参数放在JSON中即可。但有的时候,还有少许参数放在URL里面。

    演示代码:

    前端:

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>AJAX POST</title>
    		<script type="text/javascript" src="JS/jquery-3.3.1.min.js"></script>
    		
    		<style>
    			.main
    			{
    				width: 500px;
    				margin: 10px auto;    		
    			}
    			.main input,select{
    				width: 250px;
    				padding: 4px;
    				margin: 2px;
    			}
    		</style>
    	</head>
    	<body>
    		<div class="main">
    			学号: <input type='text' class='id' />  <br>  <!-- name: 即参数名 -->
    	    	姓名: <input type='text' class='name' /> <br>
    	    	手机: <input type='text' class='phone' /> <br>
    	    	性别: <select class='sex' style="width: 260px;">
    	    		<option value='male'> 男 </option>
    	    		<option value='female'> 女 </option>
    	    	</select> <br><br>
    	    	<button onclick="submit()">提交</button>
    		</div>
    	</body>
    	<script>
    		function submit()
    		{
    			var req = {};
    			
    			req.id = $(".main .id").val().trim();
    			req.name = $(".main .name").val().trim();
    			req.phone = $(".main .phone").val().trim();
    			req.sex = $(".main .sex").val().trim();
    			
    			/*在发送请求时,把请求转成json对象*/
    			var jsonStr = JSON.stringify(req);
    			console.log(jsonStr);
    			
    			$.ajax({
    				type:"POST",    /*请求类型-POST/GET*/
    				url:"AddStudent?mode=admin&token=12930289",   /*服务URI,用相对地址*/
    				data:jsonStr,          /*附加请求参数*/
    				dataType:"json",   /*期望服务器返回的数据类型*/
    				success: function(resp)  /*已经将服务器返回的数据转成JS 对象*/
    				{
    					if(resp.error==0)
    					alert("提交成功");
    					else
    					alert("出错:"+resp.reason);
    				},
    				error: function(jqXHR, textstatus, errorThrown)
    				{
    					alert("错误:" +jqXHR.status);
    				}
    			});	
    		}
    	</script>
    </html>

    后端核心代码:

    package my;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.Writer;
    import java.util.HashMap;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.json.JSONObject;
    
    /**
     * Servlet implementation class AddStudent
     */
    @WebServlet("/AddStudent")
    public class AddStudent extends HttpServlet {
    	private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public AddStudent() {
            super();
            // TODO Auto-generated constructor stub
        }
    
    	/**
    	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
    	 */
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.getWriter().append("Served at: ").append(request.getContextPath());
    	}
    
    	/**
    	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
    	 */
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
    								throws ServletException, IOException {
    		String reqText = readAsText(request.getInputStream(), "UTF-8");
    		
    		System.out.println(reqText);
    		
    		//转化为JSON
    		JSONObject jreq = new JSONObject(reqText);
    		
    		//URL末尾,由问号引导的字符串(在restful中也有部分参数在URL中
    		//例如:url:"AddStudent?mode=admin&token=12930289",   /*服务URI,用相对地址*/
    		String query = request.getQueryString();
    		System.out.println(query);
    		HashMap<String, String>ppp = parseQuery(query);
    		System.out.println(ppp);
    		
    		int id = jreq.getInt("id");
    		String name = jreq.getString("name");
    		String phone = jreq.getString("phone");
    		boolean sex = "male".equals(jreq.getString("sex")); 
    		
    		// 添加到数据库
    		Student s = new Student(id, name, sex, phone);
    		DemoDB.i.add( s );
    		
    		// 返回应答数据
    		JSONObject jresp = new JSONObject();
    		jresp.put("error", 0); // 错误码,0表示成功
    		jresp.put("reason", "OK"); // 错误原因描述, 如果没有错误则提示OK
    		response.setCharacterEncoding("UTF-8");
    		response.setContentType("text/plain");
    		Writer writer = response.getWriter();
    		writer.write( jresp.toString(2));
    		writer.close();
    		
    	}
    	
    	//从Stream中读取数据直到读取完毕
    	public String readAsText(InputStream StreamIn, String charset) throws IOException
    	{
    		ByteArrayOutputStream cache = new ByteArrayOutputStream(1024*16);
    		byte[] data = new byte[1024];
    		
    		while(true)
    		{
    			int n =StreamIn.read(data);
    			if(n<0)break;
    			if(n==0)continue;
    			
    			//缓存起来
    			cache.write(data, 0 ,n);
    			if(cache.size()>1024*512)
    				break;
    		}
    		
    		return cache.toString(charset);
    	}
    	
    	//转为HashMap
    	public HashMap<String, String>parseQuery(String query)
    	{
    		HashMap<String, String>parms = new HashMap<String, String>();
    		
    		String[] ppp = query.split("&");
    		
    		for(String p : ppp)
    		{
    			String[] kv = p.split("=");
    			
    			String key = kv[0];
    			String value = "";
    			if(kv.length>1)value = kv[1];
    			
    			parms.put(key, value);
    		}
    		
    		return parms;
    	}
    
    }
    

    四、快速创建REST服务

    -首先自定义设计一个抽象类AfSimpleREST继承与HttpServlet

    -里面定义一个抽象方法,用于子类对前端传回的JSON格式字符串的数据进行分析

    package my;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.Writer;
    
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.json.JSONObject;
    
    import af.AfWebException;
    
    public abstract class AfSimpleREST extends HttpServlet
    {
    	protected boolean enableErrorLog = false; // 是否打印异常输出
    	protected boolean niceJSONFormat = true; // 输出的JSON是否综进 (缩进影响运行效率)
    	protected int MAX_REQUEST_SIZE = 1024 * 512; // 允许上传的JSON最大长度
    	protected String charset = "UTF-8";
    	
    	// 子类须重写这个方法,进行业务处理
    	// 处理返回后,可以返回 JSONObject, JSONArray, 或int long String 等基本类型
    	protected abstract Object execute(HttpServletRequest request,
    											HttpServletResponse response,
    											JSONObject jreq)throws Exception;
    
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    										throws ServletException, IOException
    	{
    		// 无论是 GET/POST, 均统一处理
    		doPost(request, response);
    	}
    
    	@Override
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    	{
    		String requestURI = request.getRequestURI();
    		
    		
    		// 处理请求数据
    		JSONObject jresp = new JSONObject();		
    		try{
    			// 读取请求数据, 转成字符串, 转成 JSON
    			String reqText = readAsText(request.getInputStream(), charset, MAX_REQUEST_SIZE);
    			JSONObject jreq = null;
    			if(reqText.length()>0) jreq = new JSONObject(reqText);
    			
    			// 子类应重写 execute() 方法
    			Object data = execute(request, response, jreq);
    			jresp.put("error", 0); // 错误码,0表示成功
    			jresp.put("reason", "OK"); // 错误原因描述, 如果没有错误则提示OK
    			if(data != null)
    				jresp.put("data", data); // 
    		}
    		catch(AfWebException e)
    		{
    			String reason = e.getMessage();		
    			System.out.println("** 出错: " + requestURI + ", 原因: " + reason);
    			
    			if(enableErrorLog) e.printStackTrace();
    			
    			// 应签数据
    			jresp.put("error", e.error); // 错误码,0表示成功
    			jresp.put("reason", reason); // 错误原因描述, 如果没有错误则提示OK
    		}
    		catch(Exception e)
    		{
    			String reason = e.getMessage();
    			if(reason == null) reason = e.getClass().getName();			
    			System.out.println("** 出错: " + requestURI + ", 原因: " + reason);
    			
    			if(enableErrorLog) e.printStackTrace();
    			
    			// 应签数据
    			jresp.put("error", -1); // 错误码,0表示成功
    			jresp.put("reason", e.getMessage()); // 错误原因描述, 如果没有错误则提示OK
    		}
    		
    		// 是否按可读风格生成JSON ( 缩进格式 or 紧凑格式 )
    		String jsonstr = niceJSONFormat ? jresp.toString(2) : jresp.toString();
    		
    		// 发送应答给客户端
    		response.setCharacterEncoding(charset);
    		response.setContentType("text/plain");
    		//response.setHeader("Connection", "close");
    		Writer writer = response.getWriter();
    		writer.write( jsonstr );
    		writer.close();	
    	}
    	
    	public static String readAsText(InputStream streamIn, String charset, int maxSize)
    			throws IOException 
    	{
    		ByteArrayOutputStream cache = new ByteArrayOutputStream(1024*16);  
            byte[] data = new byte[1024]; 
            
            int numOfWait = 0;
            while (true)
            {
            	int n = streamIn.read(data); // n: 实际读取的字节数
            	if(n < 0) break; // 连接已经断开
            	if(n == 0) 
            	{
            		if( numOfWait ++ >= 3) break; // 此种情况不得连续3次
            		try{ Thread.sleep(5);}catch(Exception e){}
            		continue;// 数据未完 //  
            	}
            	numOfWait = 0;
    
            	// 缓存起来
            	cache.write(data, 0, n);        	
            	if(cache.size() > maxSize) // 上限, 最多读取512K
            		break;
            }  
            
            return cache.toString(charset);
    	}
    	
    
    }
    

    子类继承:

    package my;
    
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.json.JSONObject;
    
    @WebServlet("/AddBook")
    public class AddBook extends AfSimpleREST
    {
    
    	@Override
    	protected Object execute(HttpServletRequest request, 
    								HttpServletResponse response, 
    									JSONObject jreq) throws Exception
    	{
    		String id = jreq.getString("id");
    		String name = jreq.getString("name");
    		String phone = jreq.getString("phone");
    		String pub = jreq.getString("pub");
    		System.out.println("编号:"+id+"作者:"+name+"手机号:"+phone+"出版社:"+pub);
    		return null;
    	}
    
    }
    

    前端代码:

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>AJAX POST</title>
    		<script type="text/javascript" src="JS/jquery-3.3.1.min.js"></script>
    		
    		<style>
    			.main
    			{
    				width: 500px;
    				margin: 10px auto;    		
    			}
    			.main input,select{
    				width: 250px;
    				padding: 4px;
    				margin: 2px;
    			}
    		</style>
    	</head>
    	<body>
    		<div class="main">
    			书号: <br><input type='text' class='id' />  <br>  <!-- name: 即参数名 -->
    	    	书名: <br><input type='text' class='name' /> <br>
    	    	手机: <br><input type='text' class='phone' /> <br>
    	    	出版社: <br><input type='text' class='pub' /> <br><br>
    	    	<button onclick="submit()">提交</button>
    		</div>
    	</body>
    	<script>
    		function submit()
    		{
    			var req = {};
    			
    			req.id = $(".main .id").val().trim();
    			req.name = $(".main .name").val().trim();
    			req.phone = $(".main .phone").val().trim();
    			req.pub = $(".main .pub").val().trim();
    			
    			/*在发送请求时,把请求转成json对象*/
    			var jsonStr = JSON.stringify(req);
    			console.log(jsonStr);
    			
    			$.ajax({
    				type:"POST",    /*请求类型-POST/GET*/
    				url:"AddBook",   /*服务URI,用相对地址*/
    				data:jsonStr,          /*附加请求参数*/
    				dataType:"json",   /*期望服务器返回的数据类型*/
    				success: function(resp)  /*已经将服务器返回的数据转成JS 对象*/
    				{
    					if(resp.error==0)
    					alert("提交成功");
    					else
    					alert("出错:"+resp.reason);
    				},
    				error: function(jqXHR, textstatus, errorThrown)
    				{
    					alert("错误:" +jqXHR.status);
    				}
    			});	
    		}
    	</script>
    </html>

     

    展开全文
  • 一分钟理解什么是REST和RESTful

    万次阅读 多人点赞 2018-05-25 11:25:59
    amp;wfr=spider&amp;for=pc从事web开发工作有一小段时间,REST风格的接口,这样的词汇总是出现在耳边,然后又没有完全的理解,您是不是有和我相同的疑问呢?那我们一起来一探究竟吧!...知乎大神Ivony有句话说的好...
  • Restful & DRF的简单介绍

    千次阅读 2020-02-19 22:27:08
    Restful 先看REST是什么意思,英文Representational state transfer 表述性状态转移 其实就是对 资源 的表述性状态转移。 简单的说:RESTful是一种架构的规范与约束、原则,符合这种规范的架构就是RESTful架构。 ...
  • 目前市面上大部分公司开发人员使用的接口服务架构主要有:restful、rpc。 rpc: 翻译成中文:远程过程调用[远程服务调用]. http://www.lufei.com/api post请求 action=get_all_student&params=3
  • 编程是数据结构和算法的结合,而在Web类型的App中,我们对于数据的操作请求是通过url来承载的,本文详细介绍了REST规范和CBV请求流程。 编程是数据结构和算法的结合,小程序如简单的计算器,我们输入初始数据,经过...
  • Django Restful Framework 是基于 Django 框架的基于 Restful Api 的后端框架,大型项目必备 MySql 数据库,以及对应的数据可视化工具 navicat,读者自行下载 MySql navicat 如前端的 cnpm 与 npm 一样,python 环境...
  • RESTful介绍和使用教程

    万次阅读 多人点赞 2018-07-21 10:09:49
    一.REST起源 REST(Representational State Transfer)表象化状态...是Web服务的一种新的架构风格(一种思想)。 1.什么是轻量级: ... 代码不被侵入(正例:SpringMVC中不用接口和继承,仅用注解完成。反例:S...
  • rest和restful的区别

    千次阅读 2019-04-23 22:38:08
    REST服务与Restful风格 一、REST来源 REST:是一组架构约束条件和原则,REST是Roy Thomas Fielding在他2000年的博士论文中提出的。 图 1 Roy Thomas Fielding是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器...
  • RESTful 详解

    千次阅读 2018-07-15 03:34:23
    1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。... 他在论文中提到:“我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为...
  • REST面向资源架构 RESTful架构详解

    千次阅读 2017-05-25 11:54:36
    1. 什么是REST  REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。 他在...
  • 怎样理解 RESTRESTful

    千次阅读 2018-04-11 18:02:21
    本文虽然是参考别人的内容,但是是作者花很多心思整理出来,整理本文章的目的是为了自己可以好理解REST和方便其他人理解,如果要转载,请征求作者意见!一、什么是API? 为了解释清楚REST,必须理解API。API...
  • RESTRESTful风格框架

    2019-04-10 15:48:39
    转载: https://blog.csdn.net/weixin_42049777/article/details/81131819 https://blog.csdn.net/intelrain/article/details/80449371 https://blog.csdn.net/aiyaya_/article/details/78209992
  • RESTRESTFul API最佳实践

    万次阅读 2017-05-30 21:39:43
    我经常会面试一些做PHP的...但RESTFul API已经是现在互联网里对外开放接口的主流模式,可参考: 豆瓣API https://developers.douban.com/wiki/?title=api_v2 GitHub https://developer.github.com/v3/ 数一
  • RestRestful和Jersey

    2018-07-06 21:09:32
    1、什么是RESTREST不是"rest"这个单词 Representational State Transfer 直接翻译:表现层状态转移, 找到的一种最好理解的说法是:URL定位资源,用HTTP动词GET,POST,DELETE,DETC)描述操作。 ...
  • 在Dubbo中开发REST风格的远程调用
  • 什么是REST ? 什么是RESTful

    千次阅读 2019-04-04 13:34:42
    REST (REpresentation State Transfer) 描述了一个架构样式的网络系统,指的是一组架构约束条件和原则。 RESTful 指的是满足这些约束条件和原则的应用程序或设计。 RESTful service是一种架构模式,它的轻量级web...
  • webservice之REST以及RESTful的实现

    千次阅读 2017-01-22 14:34:33
    什么是REST?  REST (REpresentation State Transfer) 描述了一个架构样式的网络系统,比如 web 应用程序。...REST 指的是一组架构约束条件和原则...满足这些约束条件和原则的应用程序或设计就是 RESTful。  Web 应用程
  • REST API(RESTful)基于微服务SpringCloud项目的编程

    千次阅读 热门讨论 2019-05-08 13:06:19
    RESTful 架构风格概述 在当前互联网环境下,随着docker等技术的兴起,『微服务』的概念也越来越被大家接受并应用于实践,日益增多的web service逐渐统一于RESTful 架构风格,如果开发者对RESTful 架构风格不甚...
  • 理解并设计rest/restful风格接口

    万次阅读 多人点赞 2016-08-31 09:26:00
    网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备......)。 因此,必须有一种统一的...我以前写过一篇《理解RESTful架构》,探讨如何理解这个概
  • 【什么是RESTFULREST的请求方法有哪些,有什么区别?】 这里是修真院前端小课堂,每篇分享文从 【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战】【扩展思考】【更多讨论】【参考文献】 八个...
  • RESTRESTful(对比、规则、优缺点)

    千次阅读 2019-07-17 10:10:48
    REST 系统的特征 演化 优点&缺点 是什么? 1.传统下的API接口  http是目前在互联网上使用最多的协议,没有之一。  可是http的创始人一直都觉得,在过去10几年来,所有的人都在错误的使用Http.这句话怎么说...
  • 但是在我个人理解提供数据才是接口,而最常见的就是RESTful架构形式,在Oracle官网又看到不需接口开发直接配置的Oracle REST Data Services 即ORDS,使我更加想深入了解什么是RESTRESTful呢?介于C站知识丰富,...
  • REST以及RESTful的实现:Web API

    千次阅读 2014-07-24 17:31:43
    什么是RESTREST (REpresentation State Transfer) 描述了一个架构样式的网络系统,比如 web 应用程序。...满足这些约束条件和原则的应用程序或设计就是 RESTful。 Web 应用程序最重要的 REST
  • RESTRESTful浅谈

    千次阅读 2017-07-30 21:30:32
    越来越多的人开始意识到,网站即软件,而且是一种新型的软件。 这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点。 网站开发,完全可以...
  • Discover the RESTful technologies, including REST, JSON, XML, JAX-RS web services, SOAP and more, for building today's microservices, big data applications, and web service applications. This book is ...
  • 一篇介绍让Struts2支持REST风格的URL映射的文章...Note:不久前写了一篇文章《使用Restful2ActionMapper让Struts2支持REST风格的URL映射》,但后来发现有些不对,Struts2的Restful2ActionMapper并不按我想的那样运行...
  • 一、go-json-rest框架介绍go-json-rest(https://github.com/ant0ine/go-json-rest/)是基于net/http的一个小封装,可帮助轻松构建RESTful JSON API。它使用基于Trie的实现提供快速和可拓展的请求路由,帮助处理JSON...

空空如也

1 2 3 4 5 ... 20
收藏数 481,318
精华内容 192,527
关键字:

restful