美文网首页技术小酌
我所理解的Restful

我所理解的Restful

作者: 但我知道 | 来源:发表于2017-04-11 14:42 被阅读0次

追根溯源

理解一个概念最好的一个方法就是知其来龙去脉,最简单暴力的方式就是直接上结论。

知识并不仅仅是其表面上看起来那么枯燥乏味的,也可以很性感。就像《七堂极简物理课》的作者,虽然是个物理学家,讲的也是物理学世界里博大精深的理论,但是他以诗的语言,讲诉了物理学家发现每个理论碰到的困难和惊喜,有血有肉,让人沉浸其中。

今天,我们的主角是个IT界牛人中的牛人,意思就是BAT这样的牛人,听到这个名字,也会说,他是个牛人,自己只是个小学生。

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。Fielding何许人也,他是HTTP协议(1.0版和1.1版)的主要设计者Apache服务器软件的作者之一Apache基金会的第一任主席。这是个大牛人。

Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。翻译是"表现层状态转化", 这个概念很重要,这里划重点喽。那么,如果一个架构符合REST原则,就称它为RESTful架构

REST——表现层状态转化

REST的名称"表现层状态转化"中,省略了主语,主语就是资源(Resources)。 何谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实物。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。

表现层(Representation),"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。 比如,文本内容可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

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

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

综合上面的解释,我们总结一下什么是RESTful架构:
(1)资源用URI表示;
(2)客户端和服务器之间,在表现层进行资源的状态转换;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

接口设计误区

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

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

GET /POSTS/1

技术实现细节——网络框架

图片
  1. bean文件夹放置DTO,以后跟服务器端协定好DTO,将所有放置此处,可修改
  2. requests文件夹放置网络操作,推荐按模块区分,一个模块一个类,模块下的网络操作直接写成一个方法,可修改
  3. HttpBaseDownload实现下载方法,HttpBaseUpload实现上传方法,但我们现在不case;
  4. 接下来我们重点关注HttpBaseReq这个类,这个类封装了RestFul所需要的四个表示操作方式。

技术实现细节——核心类HttpBaseReq

看看HttpBaseReq类方法


现在直接帮你划重点啦,方法取名已经很明确了,直接按操作动作选方法。几个参数的意思在使用处再详细讲解。

挑取requestPut方法瞅两眼

public static <E> int requestGetWithDialog(Context activity, String url, E mBean, final NetProcessCallback processCallback,
                                               final NetResponseCallback callback) {
        //1. 网络请求实现
        int taskId = requestImp(url, HttpRequest.RequestMethod.GET, mBean, processCallback, callback);
        //2. 起小海快跑弹窗
        if (taskId > 0) {
            showDialog(activity, taskId);
        }
        //3. 返回网络请求唯一标示
        return taskId;
    }

这个方法与requestPostWithDialog、requestDeleteWithDialog等不同操作代码相同,不同动作的区分靠HttpRequest.RequestMethod这个枚举,Get请求传递HttpRequest.RequestMethod.GET,post请求传递HttpRequest.RequestMethod.POST。

哦,宝藏藏在requestImp,让我们继续深挖下去

private static <E> int requestImp(String url, final HttpRequest.RequestMethod requestMethod, E mBean, final NetProcessCallback
            processCallback, final NetResponseCallback callback) {
        ... ...
        //1. 将入参Bean实体转换未Json对象jsonObject
        // class -> String
        if (mGson == null) {
            mGson = new Gson();
        }
        JsonObject jsonObject = null;
        String k = null;
        if (mBean != null) {
            k = mGson.toJson(mBean);
            // string  -> JsonObject
            if (sJsonParser == null) {
                sJsonParser = new JsonParser();
            }
            jsonObject = sJsonParser.parse(k).getAsJsonObject();
            k = jsonObject.toString();
        }
        //2. get和delete动作 将url和k组合,组合成http://baidu.com?name=jack形式
        if ((requestMethod == HttpRequest.RequestMethod.GET || requestMethod == HttpRequest.RequestMethod.DELETE)
                && jsonObject != null && jsonObject.size() > 0) {
            k = null;
            // 将url和k组合
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(url);
            stringBuilder.append("?");
            for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
                stringBuilder.append(entry.getKey()).append("=").append(entry.getValue().toString()).append("&");
            }
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            url = stringBuilder.toString();
            url = url.replaceAll("\"", "");//临时替换双引号
        }

        int taskId = 0;
        //3. 调用田少的RESTful网络底层
        taskId = HttpRequest.getInstance().requestWithRESTful(url, requestMethod, getHeadJson(), k, new NetworkCallback() {
            ... ...
        });
        if (taskId <= 0) {
            callback.netFailure("请求下发失败");
        }
        return taskId;
    }

代码逻辑有点多了,帮你做个小结吧

  1. 将入参Bean实体转换未Json对象jsonObject;
  2. Delete和Get请求,需要将路径url和入参k组合,组合成http://baidu.com?value=jack 形式;
  3. Post和Patch请求,将入参作为postData数据传输。

此时我的眼睛瞄准了requestWithRESTful

public int requestWithRESTful(String url, HttpRequest.RequestMethod method, String jsonHeadLines, String bodyData, NetworkCallback networkCallbacks) {
        Log.v(Log.XH_NETWORK_CLIENT_TAG, " url=" + url);
        Log.v(Log.XH_NETWORK_CLIENT_TAG, " method=" + method);
        Log.v(Log.XH_NETWORK_CLIENT_TAG, " jsonHeadLines=" + jsonHeadLines);
        Log.v(Log.XH_NETWORK_CLIENT_TAG, " bodyData=" + bodyData);
        JSONObject jsonParam = new JSONObject();
        try {
            jsonParam.put("requestMethod", method.toString());
            if(bodyData != null && !method.equals(HttpRequest.RequestMethod.DELETE) && !method.equals(HttpRequest.RequestMethod.GET)) {
                jsonParam.put("postData", bodyData);
            }

            if(jsonHeadLines != null) {
                jsonParam.put("headList", jsonHeadLines);
            } else {
                JSONObject e = new JSONObject();
                e.put("contentType", "application/json");
                jsonParam.put("headList", e.toString());
            }
        } catch (JSONException var8) {
            var8.printStackTrace();
        }

        return this.request(url, jsonParam.toString(), networkCallbacks);
    }
  1. 田少requestMethod里存放请求动作;
  2. headList放置自行协议的请求头;
  3. postData放置非DELETE请求和非GET请求的请求数据。

协议的请求头

往回掰代码,找到getHeadJson方法

/**
     * @return 返回Header头
     */
    private static String getHeadJson() {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("Content-Type", "application/json; charset=UTF-8");
        String packageName = XHApplication.sPackageName;
        String versionName = XHApplication.sVersionName;
        String releaseName = Build.VERSION.RELEASE;
        String model = android.os.Build.MODEL;
        String suuid = XHApplication.sUUID;
        String userAgent = String.format(Locale.getDefault(), "%s/%s (%s; android; %s; %s)",
                packageName, versionName, model, releaseName, suuid);
        jsonObject.addProperty("User-Agent", userAgent);
        String session = AppConfig.get(AppConfig.KEY_SESSION);
        if(!TextUtils.isEmpty(session)){
            String auth = String.format(Locale.getDefault(), "Bearer %s", session);
            jsonObject.addProperty("Authorization", auth);
        }

        return jsonObject.toString();
    }
  1. Content-Type: 内容类型,可以有application/xml,text/xml,我们现在统一application/json;
  2. User-Agent传输设备、客户端相关的信息:

格式 User-Agent: 应用名称或包名/应用版本号 (设备型号; android|ios; 系统版本号; 5.0设备串号|U) > U表示未定义或未知
比如:User-Agent: com.xh.app.yuedu/1.0 (P350; android; 5.0; 设备串号)

  1. Authorization头传输用户认证的token:

格式 Authorization: Bearer sessionId;
如 Authorization: Bearer 4086c8d4-8ca4-42d3-a900-c9e7a5e8329d;

如何使用

一个Get请求

服务器端接口定义:



网络请求:

/**
     * des:获取文章评论列表
     * author:wqk
     * date:2017/3/9 0009 14:46
     * String exampel="http://192.168.5.29:8082/v1/articles/5/comments?userId=32673&page=0&size=10";
     */
    public static void loadArticleCommentList(Context context, RequestCommentListBean bean, NetResponseCallback callback) {
        String token = XHApplication.getXHApplication().getM();
        bean.setUserId(token);
         //0. 拼装路径
        String url = String.format(Locale.getDefault(), "%sarticles/%s/comments", NetConst.ROOT_URL, bean.getArticleId());
        HttpBaseReq.requestGetWithDialog(context, url, bean, new NetProcessCallback() {
            @Override
            public void dataProcessor(Object object) {
                 //1. String类型的数据用Gson转换成实体类数据
                ArticleCommentListResponse response = (new Gson()).fromJson(
                        object.toString(), ArticleCommentListResponse.class);
                //2. 数据存储,可存配置,存数据库,存文件
                AppConfig.put(NetConst.LOAD_ARTICLE_COMMENT_LIST_RESPONSE, response);
            }
        }, callback);
    }
  1. url的拼接需要用户usId和文章id,表示某人(UsId)获取(Get)某篇文章(ArticleId)下的评论;
  2. NetProcessCallback用作解析数据,方法是子线程调用,不阻塞主线程,里面可执行解析数据,存储数据操作;
  3. bean作为参数传入requestGetWithDialog方法,bean的数据会以key=value的方式拼接到路径的?后面。

一个Post请求

服务器接口定义:



网络请求:

/**
     * 保存评论,无数据返回,可不解析数据
     */
    public static void saveComment(Context context, SaveCommentBean bean, NetResponseCallback callback) {
        String usId = XHApplication.getXHApplication().getM();
        bean.setUserId(NumberUtil.toInt(usId));
        String url = String.format(Locale.getDefault(), "%sarticles/%s/comments", NetConst.ROOT_URL, bean.getArticleId());
        HttpBaseReq.requestPostWithDialog(context, url, bean, null, callback);
    }
  1. 无数据返回,可不解析数据,NetProcessCallback参数可传null;

一个Delete请求

服务器接口定义:

/**
     * 删除评论, ?后无数据,bean入参可传null, 无数据返回,可不解析数据
     */
public static void deleteComment(Context context, DeleteCommentBean bean, NetResponseCallback callback) {

        String url = String.format(Locale.getDefault(), "%sarticles/%s/comments/%s"
                , NetConst.ROOT_URL, bean.getArticleId(), bean.getCommentId());
        HttpBaseReq.requestDeleteWithDialog(context, url, null, null, callback);
    }

鸣谢

理解RESTful架构

相关文章

  • 我所理解的Restful

    追根溯源 理解一个概念最好的一个方法就是知其来龙去脉,最简单暴力的方式就是直接上结论。 知识并不仅仅是其表面上看起...

  • RESTFUL风格网络框架demo

    一. 我所理解的RESTFUL 1. 起源, REST这个词,是Roy Thomas Fielding在他2000...

  • RESTful API 使用解读

    理解 RESTFul 架构 RESTful API 设计指南

  • RESTful API最佳实践的一些理解

    我的个人博客,RESTful API最佳实践的一些理解 什么是RESTful 简单的说:RESTful是一种架构的...

  • restful

    理解RESTful架构

  • python(12)实践Django-Restful API

    关于Restful API,可阅读理解RESTful架构和RESTful API 设计指南。 在Django中要实...

  • RESTful架构和API设计

    理解RESTful风格 - 阮一峰RESTful设计风格指南 - 阮一峰RESTful 风格api 优点: 将接口...

  • Restful的理解

    最近的学习中开始对Rest-ful API产生兴趣,毕竟它和RPC是现在用的比较多的通信方法,姑且这么说,闲话不多...

  • Restful的理解

    REST全称是 Resource Representational State Transfer通俗来讲就是:资源...

  • RESTful的理解

    引子 大白话讲RESTful API用URL定位资源,用HTTP描述操作 API:application prog...

网友评论

    本文标题:我所理解的Restful

    本文链接:https://www.haomeiwen.com/subject/ixpyattx.html