精华内容
下载资源
问答
  • RESTful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计。 它的大原则容易把握,但是细节不容易做对。本文总结 RESTful 的设计细节,介绍如何设计出易于理解和使用的 API。 一、URL 设计 1.1 动词 + 宾语 ...

    RESTful 是目前最流行的 API 设计规范,用于 Web 数据接口的设计。

    它的大原则容易把握,但是细节不容易做对。本文总结 RESTful 的设计细节,介绍如何设计出易于理解和使用的 API。

    一、URL 设计

    1.1 动词 + 宾语
    RESTful 的核心思想就是,客户端发出的数据操作指令都是"动词 + 宾语"的结构。比如,GET /articles这个命令,GET是动词,/articles是宾语。

    动词通常就是五种 HTTP 方法,对应 CRUD 操作。

    GET:读取(Read)
    POST:新建(Create)
    PUT:更新(Update)
    PATCH:更新(Update),通常是部分更新
    DELETE:删除(Delete)
    根据 HTTP 规范,动词一律大写。

    1.2 动词的覆盖
    有些客户端只能使用GET和POST这两种方法。服务器必须接受POST模拟其他三个方法(PUT、PATCH、DELETE)。

    这时,客户端发出的 HTTP 请求,要加上X-HTTP-Method-Override属性,告诉服务器应该使用哪一个动词,覆盖POST方法。

    POST /api/Person/4 HTTP/1.1
    X-HTTP-Method-Override: PUT
    上面代码中,X-HTTP-Method-Override指定本次请求的方法是PUT,而不是POST。

    1.3 宾语必须是名词
    宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。比如,/articles这个 URL 就是正确的,而下面的 URL 不是名词,所以都是错误的。

    /getAllCars
    /createNewCar
    /deleteAllRedCars
    1.4 复数 URL
    既然 URL 是名词,那么应该使用复数,还是单数?

    这没有统一的规定,但是常见的操作是读取一个集合,比如GET /articles(读取所有文章),这里明显应该是复数。

    为了统一起见,建议都使用复数 URL,比如GET /articles/2要好于GET /article/2。

    1.5 避免多级 URL
    常见的情况是,资源需要多级分类,因此很容易写出多级的 URL,比如获取某个作者的某一类文章。

    GET /authors/12/categories/2
    这种 URL 不利于扩展,语义也不明确,往往要想一会,才能明白含义。

    更好的做法是,除了第一级,其他级别都用查询字符串表达。

    GET /authors/12?categories=2
    下面是另一个例子,查询已发布的文章。你可能会设计成下面的 URL。

    GET /articles/published
    查询字符串的写法明显更好。

    GET /articles?published=true

    二、状态码

    2.1 状态码必须精确
    客户端的每一次请求,服务器都必须给出回应。回应包括 HTTP 状态码和数据两部分。

    HTTP 状态码就是一个三位数,分成五个类别。

    1xx:相关信息
    2xx:操作成功
    3xx:重定向
    4xx:客户端错误
    5xx:服务器错误
    这五大类总共包含100多种状态码,覆盖了绝大部分可能遇到的情况。每一种状态码都有标准的(或者约定的)解释,客户端只需查看状态码,就可以判断出发生了什么情况,所以服务器应该返回尽可能精确的状态码。

    API 不需要1xx状态码,下面介绍其他四类状态码的精确含义。

    2.2 2xx 状态码
    200状态码表示操作成功,但是不同的方法可以返回更精确的状态码。

    GET: 200 OK
    POST: 201 Created
    PUT: 200 OK
    PATCH: 200 OK
    DELETE: 204 No Content
    上面代码中,POST返回201状态码,表示生成了新的资源;DELETE返回204状态码,表示资源已经不存在。

    此外,202 Accepted状态码表示服务器已经收到请求,但还未进行处理,会在未来再处理,通常用于异步操作。下面是一个例子。

    HTTP/1.1 202 Accepted
    
    {
      "task": {
        "href": "/api/company/job-management/jobs/2130040",
        "id": "2130040"
      }
    }
    

    2.3 3xx 状态码
    API 用不到301状态码(永久重定向)和302状态码(暂时重定向,307也是这个含义),因为它们可以由应用级别返回,浏览器会直接跳转,API 级别可以不考虑这两种情况。

    API 用到的3xx状态码,主要是303 See Other,表示参考另一个 URL。它与302和307的含义一样,也是"暂时重定向",区别在于302和307用于GET请求,而303用于POST、PUT和DELETE请求。收到303以后,浏览器不会自动跳转,而会让用户自己决定下一步怎么办。下面是一个例子。

    HTTP/1.1 303 See Other
    Location: /api/orders/12345
    

    2.4 4xx 状态码
    4xx状态码表示客户端错误,主要有下面几种。

    400 Bad Request:服务器不理解客户端的请求,未做任何处理。

    401 Unauthorized:用户未提供身份验证凭据,或者没有通过身份验证。

    403 Forbidden:用户通过了身份验证,但是不具有访问资源所需的权限。

    404 Not Found:所请求的资源不存在,或不可用。

    405 Method Not Allowed:用户已经通过身份验证,但是所用的 HTTP 方法不在他的权限之内。

    410 Gone:所请求的资源已从这个地址转移,不再可用。

    415 Unsupported Media Type:客户端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。

    422 Unprocessable Entity :客户端上传的附件无法处理,导致请求失败。

    429 Too Many Requests:客户端的请求次数超过限额。

    2.5 5xx 状态码
    5xx状态码表示服务端错误。一般来说,API 不会向用户透露服务器的详细信息,所以只要两个状态码就够了。

    500 Internal Server Error:客户端请求有效,服务器处理时发生了意外。

    503 Service Unavailable:服务器无法处理请求,一般用于网站维护状态。

    三、服务器回应

    3.1 不要返回纯本文
    API 返回的数据格式,不应该是纯文本,而应该是一个 JSON 对象,因为这样才能返回标准的结构化数据。所以,服务器回应的 HTTP 头的Content-Type属性要设为application/json。

    客户端请求时,也要明确告诉服务器,可以接受 JSON 格式,即请求的 HTTP 头的ACCEPT属性也要设成application/json。下面是一个例子。

    GET /orders/2 HTTP/1.1
    Accept: application/json
    3.2 发生错误时,不要返回 200 状态码
    有一种不恰当的做法是,即使发生错误,也返回200状态码,把错误信息放在数据体里面,就像下面这样。

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "status": "failure",
      "data": {
        "error": "Expected at least two items in list."
      }
    }
    

    上面代码中,解析数据体以后,才能得知操作失败。

    这张做法实际上取消了状态码,这是完全不可取的。正确的做法是,状态码反映发生的错误,具体的错误信息放在数据体里面返回。下面是一个例子。

    HTTP/1.1 400 Bad Request
    Content-Type: application/json
    
    {
      "error": "Invalid payoad.",
      "detail": {
         "surname": "This field is required."
      }
    }
    

    3.3 提供链接
    API 的使用者未必知道,URL 是怎么设计的。一个解决方法就是,在回应中,给出相关链接,便于下一步操作。这样的话,用户只要记住一个 URL,就可以发现其他的 URL。这种方法叫做 HATEOAS。

    举例来说,GitHub 的 API 都在 api.github.com 这个域名。访问它,就可以得到其他 URL。

    {
      ...
      "feeds_url": "https://api.github.com/feeds",
      "followers_url": "https://api.github.com/user/followers",
      "following_url": "https://api.github.com/user/following{/target}",
      "gists_url": "https://api.github.com/gists{/gist_id}",
      "hub_url": "https://api.github.com/hub",
      ...
    }
    

    上面的回应中,挑一个 URL 访问,又可以得到别的 URL。对于用户来说,不需要记住 URL 设计,只要从 api.github.com 一步步查找就可以了。

    HATEOAS 的格式没有统一规定,上面例子中,GitHub 将它们与其他属性放在一起。更好的做法应该是,将相关链接与其他属性分开。

    HTTP/1.1 200 OK
    Content-Type: application/json
    {
      "status": "In progress",
       "links": {[
        { "rel":"cancel", "method": "delete", "href":"/api/status/12345" } ,
        { "rel":"edit", "method": "put", "href":"/api/status/12345" }
      ]}
    }
    

    四、参考链接

    RESTful API Design: 13 Best Practices to Make Your Users Happy, by Florimond Manca
    API design, by MicroSoft Azure
    
    展开全文
  • 软件接口API规范

    千次阅读 2018-01-31 10:57:26
    软件接口API规范                                当前版本:V1.
    软件接口API规范
    
                                
     
       
     
                              
                              
     
     
                                
     
                                
     
       
     
     
     当前版本:V1.0
    版本日期:2018-01-30


     
     
     
    第一章 内存管理
    避免动态分配内存,以静态方式分配  
          说明:为提高内存管理的稳定性和可靠性,算法模块可提出内存申请请求,由外部接口进行统一分配内存,禁止在算法模块内部进行动态内存的申请和释放。  


    内存分配要求4字节对齐
          说明:内存对齐可提高数据的访问速度和效率。模块内部若是开辟大块内存,可注明要求 8 字节对齐、128 字节对齐等信息。具体到数据类型转换或数据赋值时,如 char *p; *(int*)p = 4;    此时的 p 要 32 位对齐  
    除数据表外,模块内部不允许存在全局变量  
          说明:为防止在集成中存在局部变量与全局变量同名等现象,要求模块禁止使用全局变量。建议所有变量均应归纳至句柄、参数结构体、输入出结构体三类结构体中。   【注】:模块可允许存在一些数据表作为全局变量,但数据表的命名要要与别的数据表、变量要严格区分,另外,对于大型的表须以段的形式声明,小的表以static形式定义,在模块进行提交时需进行详细的说明。


























    第二章 函数管理
    在函数入口处或者数据对齐处,添加断言语句
       说明:在PC 或嵌入式系统均支持断言语句,断言语句 assert 可以看成一个在任何系统 状态下都可以安全使用的无害测试手段,在函数入口处,利用断言可以有效检测输入参数的有效性,特别对于数据内存对齐的地方,添加断言语句能够对关心的位置进行有效的检测,避免很多隐藏的BUG 的产生。  


    函数内部/参量不许存在大型数组和结构体变量  
       说明:由于函数内部调用结构体类型变量,需将这个结构体内存空间加载到当前函数堆栈,易引起堆栈溢出等不稳定现象发生,建议在函数里内部使用临时变量或临时结构体变量不要过多。模块函数内部和参量中不允许存在大型数组/结构体类型变量,必须以数组指针/结构体指针形式存在。   
    内部函数/变量不被外部文件调用需用 static 定义  
       说明:对于文件内部的函数/变量是指当前函数/变量仅被当前文件的函数所调用,外部 函数不得调用该函数/变量,采用static关键字定义能够让编译器清楚当前函数/变量的引用范围,在外部也不需要对函数/变量进行外部声明。但注意,使用static把它局限在内部文件使用,请详细检查参数的有效性。因为static函数参数/变量,一般不需要参数检查,请调用者自行在调用处保证参数可靠。  


    建议设计高扇入、合理扇出(小于5 )的函数  
       说明:扇出是指一个函数直接调用 (控制)其它函数的数目,而扇入是指有多少上级函 数调用它。扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,如总是1,表明函数的调用层次可能过多,这样不利程序阅读和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。函数较合理的扇出(调度函数除外)通常是3-5。扇出太大,一般是由于缺乏中间层次,可适当增加中间层次的函数。扇出太小,可把下级函数进一步分解多个函数,或合并到上级函数中。当然分解或合并函数时,不能改变要实现的功能,也不能违背函数间的独立性。扇入越大,表明使用此函数的上级函数越多,这样的函数使用效率高,但不能违背函数间的独立性而单纯地追求高扇入。公共模块中的函数及底层函数应该有较高的扇入。较良好的软件结构通常是顶层函数的扇出较高,中层函数的扇出较少,而底层函数则扇入到公共模块中。   
    对函数的错误返回码要仔细、全面地处理  
      说明:  
           1. 定义所有函数的错误码信息,函数返回值必须是错误码中的一个  
           2. 函数的每种出错返回值的意义要清晰、明了、准确,防止使用者误用、理解错误  
            或忽视错误返回码。  
           3. 在开发中函数异常返回值必须有相应的处理和告警信息。 
    尽可能确保接口的简单和明了  
       说明:模块集成时不关注各个子模块,子模块的相互调用由模块内部进行操作,因此建议各子模块接口并入模块接口相应位置进行处理,当需融合多个子模块时,将子模块对应结构纳入到外部句柄、参数结构体、输入/ 出结构体中。特别的,一个模块只提供一组标准接口。  
    建议函数功能较为单一,防止循环体过于复杂  
       说明:多功能集于一身的函数,很可能使函数的理解、测试、维护等变得困难。不要设计多用途面面俱到的函数。建议一个函数只做一件事情,不要设计多用途的函数,要控制函数体的整体规模,特别注意循环体不要过于复杂   
    检查函数所有输入参数的有效性
        说明:函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入, 即非参数输入。函数在使用输入之前,应进行必要的检查。  
    编写可重入函数,尽量避免函数带有 “记忆”功能  
        说明:要保证函数的功能是可以预测且可重入的,这就要求函数只要输入数据相同就应 产生同样的输出。有“记忆”功能的函数,其行为可能是不可预测的,因为它的行为可能取决于某种 ‘“记忆状态”。这样的函数既不易于理解又不利于测试和维护。编写C/C++语言的可重入函数时,不应使用 static 局部变量,否则必须经过特殊处理,才能使函数具有可重入性。在 C/C++语言中,函数的 static 局部变量是函数的内部存储器,有可能使函数的功能不可预测,然而,当某函数的返回值为指针类型时,则必须是STATIC 的局部变量的地址作为返回值,若为 AUTO 类,则返回为野指针。建议尽量少用 static 局部变量,除非必须。  
        示例:如下函数,其返回值 (即功能)是不可预测的。  
        unsigned int integer_sum( unsigned int base )  
        {  
            unsigned int index;  
            static unsigned int sum = 0; //  注意,是 static 类型的。  
                                   //  若改为 auto 类型,则函数即变为可预测。  
            f or (index = 1; index <= base; index++)  
            {  
                sum += index;  
            }  
            return sum;  
        }  


    防止将函数的参数作为工作变量  
        说明:将函数的参数作为工作变量,有可能错误地改变参数内容,所以很危险。对必须 改变的参数,最好先用局部变量代之,最后再将该局部变量的内容赋给该参数。  
        示例:下函数的实现不太好。  
        void sum_data( unsigned int num, int *data, int *sum )  
        {  
            unsigned int count;  
            *sum = 0;  
            for (count = 0; count < num; count++)  
            {  
                *sum  += data[count]; // sum 成了工作变量,不太好。  
            }  
         }  
        若改为如下,则更好些。  
        void sum_data( unsigned int num, int *data, int *sum )  
         {  
            unsigned int count ;  
            int sum_temp;  
            sum_temp = 0;  
            for (count = 0; count < num; count ++)  
            {  
                sum_temp  += data[count];   
            }  
            *sum = sum_temp;  
         }  
    无任何数据处理的小函数建议合并到上一级
        说明:模块中函数划分的过多,一般会使函数间的接口变得复杂。所以过小的函数,特 别是扇入很低的或功能不明确的函数,不值得单独存在。  


    不要使用函数本身或函数间的递归调用
        说明:递归调用特别是函数间的递归调用 (如A->B->C->A ),影响程序的可理解性; 递归调用一般都占用较多的系统资源 (如栈空间);递归调用对程序的测试有一定影响。故除非为某些算法或功能的实现方便,应减少没必要的递归调用。  


    仔细分析模块的功能及性能需求
        说明:函数的划分与组织是模块的实现过程中很关键的步骤,如何划分出合理的函数结 构,关系到模块的最终效率和可维护性、可测性等。优化函数结构时,要遵守以下原则:  
          (1)不能影响模块功能的实现。  
          (2)仔细考查模块或函数出错处理及模块的性能要求并进行完善。  
          (3)通过分解或合并函数来改进软件结构。  
          (4)考查函数的规模,过大的要进行分解。  
          (5)降低函数间接口的复杂度。  
          (6)不同层次的函数调用要有较合理的扇入、扇出。  
          (7)函数功能应可预测。  
          (8)提高函数内聚。(单一功能的函数内聚最高)  
    说明:对初步划分后的函数结构应进行改进、优化,使之更为合理。  






























        
    第三章 代码管理  
    尽量少(不)用浮点型数据运算  
        说明:相机多采用定点型数据处理芯片,浮点型数据处理能力相对较弱,若确实需要使用浮点型数据,须注明数据范围和数据精度
    程序运算尽量简单,控制逻辑尽量简化  
        说明:建议采用减,乘,移位,与,或,非等运算;避免使用的如除法,开方,随机函 数,cos/sin/log 等操作,必要情况可用移位,查表或其他数值计算的方法替代。建议避免循环中间嵌套复杂 if~else~,  递归等语句,尽量保证嵌套的条件语句或循环语句在三层以内;避免多重循环,尽量使用简单语句。  
    注意运算符的优先级
        说明:防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。 建议用括号明确表达式的操作顺序,避免使用默认优先级。  
        示例:下列语句中的表达式  
        word = (high << 8) | low    (1)  
        if ((a | b) && (a & c))       (2)  
        if ((a | b) < (c & d))         (3)  
        如果书写为:  
        high << 8 | low  
        a | b && a & c  
        a | b < c & d  
        由于  
        high << 8 | low = ( high << 8) | low,  
        a | b && a & c = (a | b) && (a & c),  
        (1)(2)不会出错,但语句不易理解;  
    a | b < c & d = a |   (b < c) & d,(3)造成了判断条件出错。  


    用枚举或宏来替代不易理解的数字  
    示例:如下的程序可读性差。   if (Trunk[index].trunk_state == 0)  
        {  
            Trunk[index].trunk_state = 1;  
            ...  // program code  
        }  
        应改为如下形式。   
        #define TRUNK_IDLE 0  
        #define TRUNK_BUSY 1  
        if (Trunk[index].trunk_state == TRUNK_IDLE)  
        {  
            Trunk[index].trunk_state = TRUNK_BUSY;  
            ...  // program code  
        }   
    不要使用难懂的技巧性很高的语句  
    说明:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。  
        示例:如下表达式,考虑不周就可能出问题,也较难理解。  
        * stat_poi ++ += 1;  
        * ++ stat_poi += 1;  
        应分别改为如下:  
        *stat_poi += 1;  
        stat_poi++;     //  此二语句功能相当于“ * stat_poi ++ += 1; ”  
        ++ stat_poi;  
        *stat_poi += 1; // 此二语句功能相当于“ * ++ stat_poi += 1; ”   
    仔细设计结构中元素的布局与排列顺序  
    说明:合理排列结构中元素顺序,可节省空间并增加可理解性,而且这样会使结构容易 理解、节省占用空间,并减少引起误用现象  
        示例:如下结构中的位域排列,将占较大空间,可读性也稍差。  
        typedef struct EXAMPLE_STRU  
        {  
            unsigned int valid: 1;  
            PERSON person;  
            unsigned int set_flg: 1;  
        } EXAMPLE;  
        若改成如下形式,不仅可节省 1 字节空间,可读性也变好了。  
        typedef struct EXAMPLE_STRU  
        {  
            unsigned int valid: 1;  
            unsigned int set_flg: 1;  
            PERSON person ;  
        } EXAMPLE;  
    注意数据类型的强制转换  
        说明:因为数据类型转换或多或少存在危险。除非必要,最好不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或强制的转换方式作为返回值返回,在调用函数填写参数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换。   
    充分利用宏定义,但注意宏的定义格式  
      说明:定义宏可以大大增加编程效率和程序的可读性,同时也大大方便今后代码的维护对较长变量且存在多次引用时,可以用宏代替。  
         例如:  
         1.某过程中较多引用TheReceiveBuffer[FirstSocket].byDataPtr,  
            则可以通过以下宏定义来代替:  
          # define pSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr  
         2. 算法中部分变量数值可能需要全局修改,定义宏可以避免多处变量进行修改。  
         3. 但在使用过程中,要注意宏的定义格式,因此系统不对参数进行必要的检测,仅进行简单的替换。  
    特别注意指针在函数调用中的强制  
    说明  
             void  Fuc(char* pSrc,int* pDst,int n)  
              {  
                    int i;  
                    for(i=0;i<n;i++)  
                      {  
                         pDst[i]=pSrc[i];  
                      }  
              }    
             Void  main()  
              {  
                  int  Src[3]={1,2,3};  
                  int  Dst[3];  
                  Fuc(Src,Dst,3);   
              } 
                                              








    第四章 风格管理  
    头文件必须加入预编译指令
       说明:这样就会防止头文件的重复加载,建议统一采取以下头文件定义格式:      #ifndef  _FILE_MODELA_H_随机字串      #define  _FILE_ MODELA _H_随机字串  
       …….  
       #endif //_FILE_ MODELA _H_随机字串   
    请在关键位置添加注释,注释内容要清楚、明了  
        说明:注释的原则是有助于对程序的阅读理解,在该加的地方都加了,注释不宜太多也 不能太少,注释语言必须准确、易懂、简洁。   
    对外接口头文件必须具有详细的说明  
        示例:头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者、内容、 功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明。下面这段头文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。  
        /*************************************************  
          Copyright (C), 1988-1999, QianYi Tech. Co., Ltd.  
          File name:      //  文件名  
          Description:    //  用于详细说明此程序文件完成的主要功能,与其他模块  
                        //函数的接口,输出值、取值范围、含义及参数间的控  
                        //顺序、独立或依赖等关系  
         Version:         //版本号  
         Date:           //完成日期  
    *************************************************/  


    子模块的头文件应添加必要的注释和说明  
        示例:头文件需注明版权说明、版本号、生成日期、作者、模块目的/功能、主要函数及其功能、修改日志等。下面这段源文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系 (函数、表)等。  
        /**********************************************************  
          Copyright (C), 1988-1999, Unihz Tech. Co., Ltd.  
          FileName:      //  文件名  
          Description:     //  模块描述        
          Version:          //  版本信息  
          History:          //  历史修改记录  
          <author>  <time>   <version >   <desc>  
          David    96/10/12     1.0     build this moudle    
        **********************************************************/  
    说明:Description 描述本模块的功能。History 是修改历史记录列表,每条修改记录应包括修改日期、修改者及修改内容简述。
    内部子模块函数必须添加函数头
        /*************************************************  
          Function:       //  函数名称  
          Description:   //  函数功能、性能等的描述  
          Input:           //  输入参数说明,包括每个参数的作用、取值说明及参数间关系  
          Output:         //  对输出参数的说明  
          Return:         //  函数返回值的说明  
          Others:         //  其它说明  
    *************************************************/  
    模块分级及函数命名方式 
        模块一般情况下分为若干层,每层的函数命名与其对应的模块层相关。具体事例如下:  
        整个模块分为:接口层,消息处理层,
        接口层:模块对外提供的api ,如:模块初始化,模块主函数,模块反初始化
    消息处理层:模块接收消息内部处理api  

        //模块初始化函数  
       /**********************************************************************
    * 函数名称:DevMaintainInit
    * 功能描述:设备维护模块初始化
    * 输入参数:pParam -模块信息结构指针
    * 输出参数:无
    * 返 回 值: 状态码
    * 其它说明: 
    * 修改日期        版本号     修改人      修改内容
    * -----------------------------------------------    
    ***********************************************************************/
    E_StateCode DevMaintainInit(void *pParam);  
       
       //模块主函数
    /**********************************************************************
    * 函数名称:DevMaintainDestroy
    * 功能描述:设备维护模块销毁
    * 输入参数:pParam -模块信息结构指针
    * 输出参数:无
    * 返 回 值: 状态码
    * 其它说明: 
    * 修改日期        版本号     修改人      修改内容
    ***********************************************************************/
    E_StateCode DevMaintainFxn(void *pParam);


    //模块反初始化函数
    /**********************************************************************
    * 函数名称:DevMaintainDestroy
    * 功能描述:设备维护模块销毁
    * 输入参数:pParam -模块信息结构指针
    * 输出参数:pParam -模块信息结构指针
    * 返 回 值: 状态码
    * 其它说明: 
    * 修改日期        版本号     修改人      修改内容
    * -----------------------------------------------
    ***********************************************************************/
    E_StateCode DevMaintainDestroy(void *pParam);
     
    变量及结构体命名
        变量命名采用匈牙利规则,具体如下:  
          UINT8*  pSrc;          //指针前缀 p   
          UINT8   ucSrcData;   
          INT16  wSrcData;   
          UINT16  uwSrcData;   
          INT32  nSrcData;   
          UINT32  udwSrcData;   
          FLOAT  fSrcData;   
          BOOL  bFirst;  
        各模块结构体命名必须前缀模块名称  
       
    标识符的命名要清晰、明了,有明确含义
        说明:较短的单词可通过去掉“元音”形成缩写;较长的单词可取单词的头几个字母形成缩写;一些单词有大家公认的缩写。  
        示例:如下单词的缩写能够被大家基本认可。使用完整的单词或大家基本可以理解的缩 写,避免使人产生误解  
          temp  可缩写为  tmp  ;  
          flag  可缩写为  flg  ;  
          statistic  可缩写为  stat ;  
          increment 可缩写为  inc  ;  
          message 可缩写为  msg  ;   
    用具有互斥意义或相反动作的名字定义变量和函数  
        说明:下面是一些在软件中常用的反义词组。  
        add / remove       begin / end        create / destroy   
        insert / delete       first / last         g et / release  
        increment / decrement                 put / get  
        add / delete         lock / unlock      open / close  
        min / max          old / new         start / stop  
        next / previous      source / target     show / hide  
        send / receive       source / destination  
        cut / paste          up / down  
        示例:  
        int  min_sum;  
        int  max_sum;  
        int  add_user( BYTE *user_name );  
    int  delete_user( BYTE *user_name );   
    函数体代码长度不能超过300 行
        说明:过长代码请根据程序功能模块的设计进行函数肢解。不包括注释和空格行。
    函数不能超过5 层,参量个数不能超过6 个  
        说明:目的减少函数间接口的复杂度。函数调用层数越少越好,层数过多,导致函数堆 栈的压力很大,易发生堆栈溢出。避免设计多参数函数,不使用的参数从接口中去掉,建议以 2-4 为最佳。  
    程序块要采用缩进风格编写,缩进的空格数为 4 个
    说明:对于由开发工具自动生成的代码可以有不一致。另外,保持适度的空行。


    较长的语句(>80 字符)要分成多行书写  
        说明:长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行 要进行适当的缩进,使排版整齐,语句可读。  
        示例:  
        perm_count_msg.head.len = NO7_TO_STAT_PERM_COUNT_LEN  
                                  + STAT_SIZE_PER_FRAM * sizeof( _UL );  
        act_task_table[frame_id * STAT_TASK_CHECK_NUMBER +  
        index].occupied  
                      = stat_poi[index].occupied;  
        act_task_table[taskno].duration_true_or_false  
                      = SYS_get_sccp_statistic_state( stat_item );  
        report_or_not_flag = ((taskno < MAX_ACT_TASK_NUMBER)  
                              && (n7stat_stat_item_valid (stat_item))  
                              && (act_task_table[taskno].result_data != 0));  


    一行只写一条语句  
        示例:如下例子不符合规范。  
        rect.length = 0;  rect.width = 0;  
        IVS_parm *pA,pB,pC;  
        应如下书写  
          rect.length = 0;  
          rect.width  = 0;  
          IVS_parm *pA;  
          IVS_parm *pB;  
          IVS_parm *pC;  
    注意部分语句的排版  
        说明:if、for、do、while、case、switch、default 等语句自占一行,且 if、for、do、while 等语句的执行语句部分无论多少都要加括号{}。   示例:如下例子不符合规范。  
        if (pUserCR == NULL) return;   
        应如下书写:  
        if (pUserCR == NULL)  
        {  
            return;  

    谨慎使用64 位数据处理类型和方式  
        说明:在 PC 环境下存在_int64 而在 嵌入式里需定义 long long 类型,一般建议在 PC 开发环境避免使用 64 为数据操作,除非必要。另外,对于 64 位数据赋值一定要保证数据的起始地址在 64 位数据对齐的位置。  
    例如:采用如下格式进行 64 位数据赋值,由于 h->mb.cache.mv 的数据指针不能保证 64 位数据对齐,导致数据赋值存在问题。  
          *(uint64_t*)h->mb.mv[0][i_mb_4x4+y*s4x4+0] =  
          *(uint64_t*)h->mb.cache.mv[0][x264_scan8[0]+8*y+0];  
          因此,对于以上问题,解决途径有两个:第一,保证指针地址的 64 位数据对齐;第二, 逐个字节对数据进行赋值。  
       注: float 与 double 的区别,建议均采用float 类型。  
    局部变量/指针在定义的同时应当初始化  
          说明:对于局部变量/指针建议在定义时同时完成初始化,防止使用未初始化的变量/ 指针出现在赋值语句的右边。特别对于 PC 的静态 static 变量或常量在程序的运行时自动初始化为 0,而在嵌入式环境下系统没有进行初始化,为避免这方面导致的差异,要求数据定义时必须同时完成初始化工作。  
















































    第五章效率管理
    改进数据结构的划分和组织,提高空间效率  
        说明:这种方式是解决软件空间效率的根本办法。  
        示例:如下记录学生学习成绩的结构不合理。  
        typedef unsigned char  BYTE;  
        typedef unsigned short WORD;  
        typedef struct STUDENT_SCORE_STRU  
            BYTE name[8];  
            BYTE age;  
            BYTE sex;  
            BYTE class;  
            BYTE subject;  
            float score;  
        } STUDENT_SCORE;  
        因为每位学生都有多科学习成绩,故如上结构将占用较大空间。应如下改进 (分为两个结构),总的存贮空间将变小,操作也变得更方便。  
        typedef struct STUDENT_STRU  
        {  
            BYTE name[8];  
            BYTE age;  
            BYTE sex;  
            BYTE class;  
        } STUDENT;  
        typedef struct STUDENT_SCORE_STRU  
        {  
            WORD student_index;  
            BYTE subject;  
            float score;  
    } STUDENT_SCORE;  
    循环体内工作量最小化  
    说明:应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的时间效率。  
        示例:如下代码效率不高。  
        for (ind = 0; ind < MAX_ADD_NUMBER; ind++)  
        {  
            sum += ind;  
            back_sum = sum; /* backup sum */  
        }  
        语句“back_sum = sum;”完全可以放在 for 语句之后,如下。  
        for (ind = 0; ind < MAX_ADD_NUMBER; ind++)  
        {  
            sum += ind;  
        }  
    back_sum  = sum; /* backup sum */  
    在多重循环中,应将最忙的循环放在最内层, 
        说明:减少 CPU 切入循环层的次数。  
        示例:如下代码效率不高。  
        for (row = 0; row < 100; row++)  
        {  
            for (col = 0; col < 5; col++)  
            {  
                sum += a[row][col];  
            }  
        }  
        可以改为如下方式,以提高效率。  
        for (col = 0; col < 5; col++)  
        {  
            for (row = 0; row < 100; row++)  
            {  
                sum += a[row][col];  
            }  
        }  
    对于多维数组的循环遍历建议“先行后列”的顺序  
        说明:对于多维数组来说,“先行后列”的遍历效率肯定好于 “先列后行”遍历,不论 其行数远大于列数还是情况相反甚至接近,即使在最坏的情况下也至少与 “先列后行” 遍历的效率相当。影响效率的实际上主要是大型数组导致的内存页面交换次数以及Cache 的命中率的高低,而不是循环次数本身。  
    示例:如下代码效率不高。  
        int  array[1024][512]  
        for (row = 0; row < 1024; row++)  
        {  
            for (col = 0; col <512; col++)  
            {  
                sum += a[row][col];  
            }  
        }  
        可以改为如下方式,以提高效率。  
        for (col = 0; col <512; col++)  
        {  
             for (row = 0; row < 1024; row++)  
             {  
                  sum += a[row][col];  
            }  
         }  
    尽量减少循环嵌套层次,避免循环体内含判断语句
        说明:目的是减少判断次数。循环体中的判断语句是否可以移到循环体外,要视程序的具体情况而言,一般情况,与循环变量无关的判断语句可以移到循环体外,而有关的则不可以,应将循环语句置于判断语句的代码块之中。   示例:如下代码效率稍低。  
        for (ind = 0; ind < MAX_RECT_NUMBER; ind++)  
         {  
            if (data_type == RECT_AREA)  
            {  
                area_sum += rect_area[ind];  
            }  
            else  
            {  
                rect_length_sum += rect[ind].length;  
                rect_width_sum += rect[ind].width;  
            }  
         }  
         因为判断语句与循环变量无关,故可如下改进,以减少判断次数。  
         if (data_type == RECT_AREA)  
         {  
            for (ind = 0; ind < MAX_RECT_NUMBER; ind++)  
            {  
                area_sum += rect_area[ind];  
            }  
         }  
        else  
         {  
            for (ind = 0; ind < MAX_RECT_NUMBER; ind++)  
            {  
                rect_length_sum += rect[ind].length;  
                rect_width_sum  += rect[ind].width;  
            }  
         }  


    尽量用乘法或其它方法代替除法  
       说明:浮点运算除法要占用较多 CPU 资源。  
       示例:如下表达式运算可能要占较多 CPU 资源。  
         #define PAI 3.1416  
         radius = circle_length / (2 * PAI);  
        应如下把浮点除法改为浮点乘法。  
         #define PAI_RECIPROCAL (1 / 3.1416 ) // 编译器编译时,将生成具体浮点数  
         radius = circle_length * PAI_RECIPROCAL / 2;    






















































    第六章 BUG 管理管理  
    防止内存操作越界 
        说明:内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件系统主要错误之一,后果往往非常严重,所以当我们进行这些操作时一定要仔细小心。      示例:假设某软件系统最多可由 10 个用户同时使用,用户号为 1-10,那么如下程序存在问题。  
        #define MAX_USR_NUM 10  
        unsigned char usr_login_flg[MAX_USR_NUM]= "";  
        void set_usr_login_flg( unsigned char usr_no )  
        {  
            if (!usr_login_flg[usr_no])  
            {  
                usr_login_flg[usr_no]= TRUE;  
            }  
        }  
        当 usr_no 为 10 时,将使用 usr_login_flg 越界。可采用如下方式解决。  
        void set_usr_login_flg( unsigned char usr_no )  
        {  
            if (!usr_login_flg[usr_no - 1])  
            {  
                usr_login_flg[usr_no - 1]= TRUE;  
            }  
    }  
    务必增加严重的异常处理机制  
    说明:在程序中内存处理和函数返回值的位置处增加数据异常和出错的异常处理机制能 有效跟踪 BUG 的位置。


    系统运行之初,要对数据进行一致性检查  
    说明:使用不一致的数据,容易使系统进入混乱状态和不可知状态。系统运行之初,要 初始化有关变量及运行环境,防止未经初始化的变量被引用,系统运行之初,要对加载到系统中的数据进行一致性检查
    编程时,要防止差1 错误  
        说明:此类错误一般是由于把“<=”误写成“<”或“>=”误写成“>”等造成的,由此引起的后果,很多情况下是很严重的,所以编程时,一定要在这些地方小心。当编完程序后, 应对这些操作符进行彻底检查。  
    要时刻注意易混淆的操作符  
       说明:形式相近的操作符最容易引起误用,如 C/C++中的“=”与“==”、“|”与“||”、“&”与“&&”等,若拼写错了,编译器不一定能够检查出来。当编完程序后,应从头至尾检查一遍这些操作符,以防止拼写错误。   示例:如把“&”写成“&&”,或反之。  
         ret_flg = (pmsg->ret_flg & RETURN_MASK);    
        被写为:  
         ret_flg = (pmsg->ret_flg && RETURN_MASK);  
         rpt_flg = (VALID_TASK_NO( taskno ) && DATA_NOT_ZERO( stat_data ));  
        被写为:  
         rpt_flg = (VALID_TASK_NO( taskno ) & DATA_NOT_ZERO( stat_data ));  
    保留switch 语句下的 default 分支和 break 语句  
    说明:可能的话,if语句尽量加上 else 分支,对没有else 分支的语句要小心对待;switch 语句必须有 default 分支,对于每一个 case 下面均有一个 break 语句。 
    时刻注意表达式是否会上溢、下溢  
        示例:如下程序将造成变量下溢。  
         unsigned char size ;  
        while (size-- >= 0) //  将出现下溢  
         {  
            ... // program code  
         }  
         当 size 等于 0 时,再减 1 不会小于 0,而是 0xFF,故程序是一个死循环。应如下修改。  
        char size; //  从 unsigned char  改为 char  
        while (size-- >= 0)  
         {  
            ... // program code  
         }  
    使用变量时要注意其边界值的情况  
        示例:如 C 语言中字符型变量,有效值范围为-128 到 127。故以下表达式的计算存在一定风险。       char chr = 127;  
        int sum = 200;       chr += 1; // 127 为 chr 的边界值,再加 1 将使 chr 上溢到-128,而不是 128。  
        sum += chr; //  故 sum 的结果不是 328,而是 72。  
        若 chr 与 sum 为同一种类型,或表达式按如下方式书写,可能会好些。  
        sum = sum + chr + 1;  
    展开全文
  • API 接口鉴权规范

    千次阅读 2019-03-05 09:49:55
    Api 接口鉴权规范-1.0-md5签名 Api 登录,采用Auth鉴权方式验证API请求合法性,即所有API Http Header请求需包含以下公共参数: 1.Epay-Auth-User-Id 用户Id 2.Epay-Auth-Timestamp 请求时客户端时间错...

    设计原则:接口无状态(幂等),兼容各个客户端(app-ios/app-android/mweb/小程序等等)

    Api 接口鉴权规范-1.0-md5签名

     

    Api 登录,采用Auth鉴权方式验证API请求合法性,即所有API Http Header请求需包含以下公共参数:

    1. Epay-Auth-User-Id 用户Id

    2. Epay-Auth-Timestamp 请求时客户端时间错,以此设置过期时间

    3. Epay-Auth-Type 授权类型(AUTH_BASE[无需登录]/AUTH_USER)

    4. Epay-Auth-Sign 客户端根据签名规则生成的加密串

    5. appSecret(该字段不在Http header 传输,由客户端和服端约定好,版本一旦发布,不可更换)Api交互的通讯密钥,比如:“AWRDuwh!@!#!asd” 区分大小写

     

    签名规则:

    AUTH_BASE

    MD5(SECRET_KEY + timestamp + userId + getToken(Long.parseLong(userId)))

    AUTH_USER 

    MD5(SECRET_KEY + timestamp)

     

    Api 接口鉴权规范-2.0-jwt-token

     

    Api 登录,采用Auth鉴权方式验证API请求合法性,即所有API Http Header请求需包含以下公共参数:

    1. Epay-Auth-User-Id 用户Id

    2. Epay-Auth-Timestamp 请求时客户端时间错,以此设置过期时间

    3. Epay-Auth-Type 授权类型(AUTH_BASE[无需登录]/AUTH_USER)

    4. Epay-Auth-Token 客户端根据签名规则生成的加密串

    5. 登录成功之后服务端会返回token(jwt-token),AUTH_USER 所有请求都带着该token

    6. 其他参数channel(ios/android...)/sys-version/sys-model/geo/deviceid/area

     

    展开全文
  • API接口规范

    千次阅读 2018-03-13 13:22:54
    接口规范:1.使用HTTPs协议,确保交互数据的传输安全2.应该尽量将API部署在专用域名之下,如:https://api.example.com3.应该将API的版本号放入URL中,如:https://api.example.com/v{n}/4.网址中不能有动词,只能有...
    接口规范:
    
    1.使用HTTPs协议,确保交互数据的传输安全
    2.应该尽量将API部署在专用域名之下,如:https://api.example.com
    3.应该将API的版本号放入URL中,如:https://api.example.com/v{n}/
    4.网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。
    一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数,如:https://api.example.com/v1/products
    5.对于资源的具体操作类型,由HTTP动词表示,常用的HTTP动词有四个。
    GET(SELECT):从服务器取出资源(一项或多项)。
    POST(CREATE):在服务器新建一个资源。
    PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
    DELETE(DELETE):从服务器删除资源。
    如:GET/products:列出所有商品
    6.如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。
    下面是一些常见的参数。
    ?limit=10:指定返回记录的数量
    ?offset=10:指定返回记录的开始位置。
    ?page=2&per_page=100:指定第几页,以及每页的记录数。
    ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
    ?producy_type=1:指定筛选条件
    7.传入参数分为4种类型:
    1)地址栏参数
    * restful 地址栏参数 /api/v1/product/122 122为产品编号,获取产品为122的信息
    * get方式的查询字串 见过滤信息小节
    2)请求body数据
    3)cookie
    4)request header
    cookie和header 一般都是用于OAuth认证的2种途径
    8.返回数据
    接口返回模板:
    {
        status:0,
        data:{}||[],
        msg:’’

    }


    备注:欢迎加入web前端求职招聘qq群:668352707


    展开全文
  • 一 总则 1.编写目的 2.适用范围 ...二 接口统一规范说明 1.接口请求地址说明 2.平台公共参数说明 3.接口请求内容说明 4.接口返回内容说明 5.接口默认调用地址说明 • 正式环境 • 测试环境 三 接口详情 附录
  • Restful API 接口规范

    千次阅读 2020-09-09 22:35:23
    文章目录Restful API 接口规范背景什么是RESTful架构呢?RESTful API 设计 Restful API 接口规范 暑假期间接触到实际开发项目对开发过程中遇到的Restful接口规范存在疑惑,由于当时主要目的是尽快本地运行项目,尝试...
  • RESTful api接口规范

    万次阅读 多人点赞 2017-01-11 10:40:00
    整体规范建议采用RESTful 方式来实施。   协议 API与用户的通信协议,总是使用HTTPs协议,确保交互数据的传输安全。   域名 应该尽量将API部署在专用域名之下。 https://api.example.com 如果确定API很...
  • JMS接口API和技术规范

    千次阅读 2020-04-29 16:22:29
    JMS(JAVA Message Service,java消息服务API是Java平台上有关面向消息中间件(MOM)的技术规范,2001年6月25日sun公司发布第一个版本,后经过多次完善。它是一个接口和语义的集合,这些语义定义了应用程序组件基于...
  • 公众号头条文章数据接口 API

    千次阅读 2020-03-06 17:47:34
    之前在社区给大家免费开放了以下数据接口无限制的调用权限: 这次,再次给大家提供了一个公众号头条文章数据的 API,供大家调用、测试、开发自己的 App 使用。 1. 产品功能 此次开放了提供日更新的公众号头条文章...
  • API接口签名规范

    千次阅读 2018-12-11 11:08:55
    背景:为了增加接口参数安全,对接口参数加盐进行签名校验。 原理:客户端对传送的参数字典排序后,进行md5签名。服务器接收参数后,同理进行参数字典排序后md5签名。若客户端与服务端的签名一致,说明参数未被篡改...
  • RESTful API接口设计标准及规范

    万次阅读 多人点赞 2019-01-12 11:42:10
    RESTful发展背景及简介 网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板...RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。 REST(Representational Stat...
  • APP的数据来源就是API接口,所以API接口对于APP的意义来说不言而喻。 设计API接口最重要的考虑点就是安全机制。 我们这边将从三个方面来考虑怎么设计一个安全的API接口。 防篡改 防篡改就是防止请求的URL参数值发送...
  • API接口规范完整版本

    万次阅读 2018-04-30 17:24:55
     协议API与用户的通信协议,总是使用HTTPs协议,确保交互数据的传输安全。 域名应该尽量将API部署在专用域名之下。https://api.example.com如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。...
  • 【流程规范API接口文档规范

    千次阅读 2018-07-06 14:37:18
    接口名称 前置主动还款申请(/payBill) 接口描述 接口地址:https://api.yidianfenqi.net/payBill 返回格式:json 请求方式:GET/ POST 请求示例:https://api.yidianfenqi.net/payBill?key=123456&...
  • 系统API接口规范

    万次阅读 2017-08-24 09:17:14
    随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构势在必行。 u 单一应用架构 Ø 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。 u...
  • 文章目录通用规范版本号请求参数返回值接口变更API格式传统格式RestFul API 通用规范 版本号 每一组API接口需要对应一个大版本号,大版本号一般是跟app的大版本对应的。 比如app第一版本我们叫v1,app第二版本经过...
  • PHP:API 接口规范完整版本

    万次阅读 2016-08-02 15:22:54
    整体规范建议采用RESTful 方式来实施。 协议 API与用户的通信协议,总是使用HTTPs协议,确保交互数据的传输安全。 域名 应该尽量将API部署在专用域名之下。 https://api.example.com 如果确定API很...
  • 上海联通位置定位平台所使用的接口协议,sp与上海本地定位平台之间的请求协议。
  • API接口数据统一格式返回

    千次阅读 2019-11-13 16:53:00
    API接口数据统一格式返回新建状态码枚举类新建一个返回体类控制层 新建状态码枚举类 一般都有code(状态码)和message(提示信息)这两个属性 public enum ResultCode { //成功 SUCCESS(1,"成功"), //参数错误...
  • 您观看课程学习后 免费入群领取【超全Python资料包+17本学习电子书】 真实案例实战python数据分析。是少见的一条龙从数据抓取—清洗—分析—绘图讲解,都是实际案例,让你了解数据分析清洗挖掘的最快途径。通过学习...
  • odoo rest api 服务接口

    千次阅读 2020-05-20 22:01:55
    一、REST_API 是前后端分离最佳实践, 是开发的一套标准或者说是一套规范,不是框架。...odoo oca 已经为这样的接口提供了标准的 api 写法 rest-framework 此时我们则可以规则开发出自己业务所需要的
  • 因为是接口框架,首先要做的就是制定接口规范,好的接口规范能约束开发人员,能降低前后端人员之间的沟通协调,能避免后期联调带来的一系列问题。 1.接口规范 接口规范包含以下内容: 1、请求类型及参数 2、返回值及...
  • 税控发票开票软件发票信息数据接口规范V4.0,增值税普通发票(电子)企业端(单机版数据文件)接口规范V1.1,增值税普通发票(电子)企业端(服务器版可编程)接口规范V1.1。国家税务总局最新发票接口规范,含电子...
  • 【RESTful】RESTful API 接口设计规范 | 示例

    万次阅读 多人点赞 2018-10-28 20:57:24
    例如:设计一套API,为多个终端服务。 设计概念和准则 网络上的所有事物都可以被抽象为资源 每一个资源都有唯一的资源标识,对资源的操作不会改变这些标识 所有的操作都是无状态的(本次操作、下次操作、上次操作...
  • 一个基于Thinkphp5+phpQuery 网络爬虫抓取数据接口 统一输出接口数据api.适合正在学习Vue,AngularJs框架学习 开发demo,需要接口并保证接口不跨域的问题,新闻分类(头条/军事/娱乐/体育/科技/艺术/教育/要闻)数据接口...
  • 正确规范api接口文档

    千次阅读 2019-06-06 10:28:59
    一.正规的团队合作或者是项目对接,接口文档是非常重要的,一般.../api/user/login/ 请求方式 GET – – – 参数 是否必填 说明 phone 是 手机号码 password 是 密码 – – – 返回结果 说 明 su...
  • 接口API文档

    千次阅读 2020-12-12 17:00:37
    1.接口文档是什么 在项目开发汇总,web项目的前后端是分离开发的。...要了解接口文档的规范,首先要了解接口接口分为四部分:请求方法、url、请求参数、返回参数: 1)方法:常用的方法就是下面的四种:GET PUT

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 206,287
精华内容 82,514
关键字:

数据服务接口api规范