HTTP协议小结

写在前面

本文是阅读了《图解HTTP》一文同时本周也在一个小团体内进行了一些HTTP协议的讨论,感觉对于HTTP协议的理解比以前又加深了不少。

历史

以下材料选自《图解HTTP》:

在学习Http协议之前首先看一下他的历史,也许能解答我们不少的问题。

1989年3月,互联网还只属于少数人。在这一互联网的黎明期,HTTP诞生了。CERN(欧洲核子研究组织)的蒂姆·伯纳斯-李(Tim BernersLee)博士提出了一种能让远隔两地的研究者们共享知识的设想。

最初设想的基本理念是:借助多文档之间的相互关联形成的超文本(Hyper Text),连成可相互参阅的WWW(World Wide Web,万维网)。WWW这一名称,是Web浏览器用来浏览超文本的客户端应用程序时的名称。现在则用来表示这一系列的集合,也可简称为Web

  • HTTP/0.9
    HTTP于1990年问世。那时的HTTP并没有作为正式的标准被建立。现在的HTTP其实含有HTTP1.0之前版本的意思,因此被称为HTTP/0.9。

  • HTTP/1.0
    HTTP正式作为标准被公布是在1996年的5月,版本被命名为HTTP/1.0,并记载于RFC1945。虽说是初期标准,但该协议标准至今仍被广泛使用在服务器端。

  • HTTP/1.1
    1997年1月公布的HTTP/1.1是目前主流的HTTP协议版本。当初的标准是RFC2068,之后发布的修订版RFC2616就是当前的最新版本。

HTTP协议的根基

在了解HTTP协议之前,首先对整个计算机网络协议做一个大致的了解。首先要提到的是ISO指定的OSI七层模型,但是这个参考模型过于庞大、复杂。与此相对的是技术人员自己开发的TCP/IP协议族获得了更广泛的应用。

TCP/IP参考模型

对于我们应用端程序员来说,接触最多的还是应用层的协议,HTTP协议也是属于这一层的。但是HTTP协议是基于传输层协议的,传输层的协议是TCP和UDP协议,使用TCP协议连接会经历三次握手,而UDP不会。HTTP协议是基于可靠的TCP协议的,关于TCP/IP我们需要了解的东西暂时就到这了。更多的可以自己去看《TCP/IP详解 卷1》。最初HTTP协议的出现时为了解决WEB间数据问题的,时至今日,因为他简单的特性已经被用于各种场景了(比如咱Android和IOS,虽然以后可能会被https取代。。),所以在具体了解HTTP协议的时候,你可能会发现很多东西是你平时用不上的,这都是很正常的。

HTTP首部

HTTP协议的请求响应报文中必定包含HTTP首部,只是我们平时在使用Web的过程中感受不到它。
HTTP报文的结构:
报文首部 + 空行 + 报文主体

HTTP请求报文
在请求中,HTTP报文由方法、URI、HTTP版本、HTTP首部字段等部分构成。
报文首部构成:请求行 + 请求首部字段 + 通用首部字段 + 实体首部字段 + 其他
其中:请求首部字段+通用首部字段+实体首部字段就是HTTP首部字段。

让我们通过一个简单的请求看一下:

简书

首先我在浏览器输入的=>jianshu.com
上面的General可以看到一个Status Code:301,这个状态码代表的意思就是永久性重定向。该状态码表示请求的资源已经被分配了新的URI,希望用户(本次)能使用新的URI访问,那为啥呢?因为我输的是jianshu.com,但是实际上简书的域名是www.jianshu.com

另外在HTTP协议中状态码是一个比较重要的东西,我们通常需要根据状态码来得到一些基本的信息,比如说本次请求是否成功。那么简单的罗列一下HTTP协议中的一些状态码:

1XX 信息性状态码 接收的请求正在处理
2XX 成功状态码 请求正常处理完毕
3XX 重定向状态码 需要进行附加操作已完成请求
4XX 客户端错误状态码 服务器无法处理请求
5XX 服务器错误状态 服务器处理请求出错

以上是对状态码的一些简介,如果你想要了解更详细的,可以自行google。

HTTP首部字段结构
HTTP首部字段是由首部字段名和字段值构成的,中间用冒号“:”分割。

首部字段名:字段值
例如,在HTTP首部中以Content-Type这个字段来表示报文主体的对象类型。
Content-Type:text/html
就以上述示例来看,首部字段名为Content-Type,字符串text/html是字段值。

另外,字段值对应单个HTTP首部字段可以有多个值,入下所示
Keep-Alive:timeout=15,max=100

HTTP
HTTP
HTTP
HTTP

除了以上HTTP/1.1协议(RFC2616)中规定的47种首部字段,还有一些非正式的首部字段,这些字段被统一归纳在RFC4229 HTTP Header Field Registrations中。常用的Cookie、SetCookie和Content-Disposition等。

看了以上那么多首部字段,是不是有些眼花缭乱?其实根本没有那么复杂……对于我们android开发者来说,在平时的应用场景中只要知道Content-Type和Cookie就能应付大部分场景了。首先Cookie这玩意一般是用来验证用户身份的。众所周知HTTP协议是一个无状态协议,是不能记住用户的。Cookie应运而生,而在现在,一般来说在服务器端会将用户记录入一个session,而在你登录的请求中,服务器会返回一个cookie,这时候就需要我们去拿到这个cookie并在每一次请求中都加入了。通常这个cookie是一个session id,当然了,如果你们服务端的大兄弟返一个token给你,让你加在请求头里,那也随他开心,他要咱怎么做,咱就配合就成了。Content-Type是指明请求实体的媒体类型,具体的值可以在用到的时候自行去查找。

简单的请求

接下来使用Okhttp来进行一些简单的请求:

        //GET请求
        Request getRequest = new Request.Builder()
                .url("https://www.baidu.com")
                .build();
        Call call = mOkhttpClient.newCall(getRequest);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                System.out.println(response.body().string());
            }
        });

首先这是一个最简单的GET请求,首先创建一个请求Request,再创建一个Call,最后将这个请求调度这个call,最终你可以在onResponse这个回调里处理响应报文。这里有一个小地方值得注意,不要重复使用response.body().string(),当然如果你有需要,可以先将他赋给一个String的引用,不然第二次使用它的时候可能为空。这一点在我使用的时候还是这样,各位看官对于为什么这样感兴趣的话可以去搜搜。

再来一个普通的表单请求:

        //表单请求
        FormBody formBody = new FormBody.Builder()
                .add("name","18255697137")
                .add("pass","123")
                .build();

        Request postFormRequest = new Request.Builder()
                .url(...)
                .post(formBody)
                .build();

        Call postFormCall = mOkhttpClient.newCall(postFormRequest);
        postFormCall.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String str = response.body().string();
                System.out.println(str);
                testText.setText(str);
            }
        });

    }

与上面的GET请求对比,可以看出多了构建请求实体的步骤,这里我模拟登陆的场景,提交明文的账号密码。先说说我对于这种构建请求的看法:

  • 步骤很清晰,很HTTP
  • 用起来着实麻烦

对于Okhttp进行封装的库我用过两个,一个是OkhttpUtils,是鸿洋大神的作品,另一个就是Square的Retrofit了。OkhttpUtils好用是挺好用的,链式api,构建一个HTTP请求非常简单,但是对于RxJava和响应与实体转换的支持并不是很好,所以我个人更倾向于Retrofit。

那么用Retrofit+RxJava构建一个表单请求会是怎样的呢?

首先定义一个ApiStore接口,里面包含了一个register方法

public interface ApiStore {
    /**
     * 注册
     */
    @FormUrlEncoded
    @POST("api.php?action=register")
    Observable<BaseResponse> register(
            @Field("name")String username
            ,@Field("pass")String password);
}

     

定义一个接收数据的类型:

public class BaseResponse {
    int code;
    String message;

    @Override
    public String toString() {
        return "the code is--->" + code + "\n" +
                "the message is--->" + message;
    }
}

发送请求:

        TextView testText = (TextView) findViewById(R.id.test);
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASEURL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();


        ApiStore apiStore = retrofit.create(ApiStore.class);
        apiStore.register("182*******7","123")
                .subscribeOn(Schedulers.io())
                .map(BaseResponse::toString)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(testText::setText,Throwable::printStackTrace);

效果图:

效果图

可能你看了我对于Retrofit的使用,感觉这不比Okhttp的使用还要麻烦么。。。其实不是的,一是现在演示的都是很基础简单的东西,一是我也是刚上手Retrofit,应该还可以进一步的封装。

关于Okhttp的使用暂时就到这,本文并非专门总结Okhttp使用方法的,只是顺带一提。今天在讨论完HTTP的一些东西之后,突然又聊了一些HTTP安全方面的东西。众所周知,HTTP是明文传输的,因为在以前通常请求的都是一些资源文件,没有什么加密的必要。但是现在用在移动客户端,这还是挺要命的。有的小伙伴就说了,他们那用MD5……

首先我们想清楚MD5是干什么的,MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。MD5并不是一个加密算法,所以你用MD5处理数据传到服务端是没什么卵用的,只不过是把人能看懂的字符弄成人理解不了的字符串而已。这有啥,我模拟你登录的时候,我直接把你MD5处理过的字符串加上来不就成了,你服务器认这个不就OK?

所以在传输重要数据时可以考虑使用https或者非对称加密,为毛是非对称加密呢。。。因为如果是对称加密,那么客户端会留有一个公钥,这有点不靠谱。。。客户端的安全保障。。。当然你可以把密钥放到so里面,但是我没做过,不知道这样到底安不安全。。。

接下来是关于GET和POST这两种请求的区别:
来自WebTechGarden

  • GET请求在URL中传送的参数是有长度限制的,而POST没有。
  • GET参数通过URL传递,POST放在Request body中
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

以上的回答可能是你见的最多的答案了,可是那篇文的作者给出了从另一个角度得出的结论:GET和POST本质上没有区别。
GET和POST是HTTP协议中两种发送请求的方法,而HTTP协议是基于TCP/IP关于数据如何在万维网中如何通信的协议。如果你要给GET加上request body,给POST带上url参数,技术上是完全行得通的。

更多的内容自行戳上面的链接,我这只是给个引子~

本次的HTTP小结就暂时告一段落~

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容