Get请求 - 无参数
上一章我们学习了网络的基本概念,我们知道 URL
能输入到浏览器地址栏中被打开,
那么能不能在程序中发送请求,获取结果呢?
例如“中国科学技术大学”的网站(https://www.ustc.edu.cn/
):
Java
功能非常强大,用来实现抓取网站内容也非常简便。那么是如何实现它的呢?
安装依赖库
首先,我们需要安装一个库: Okhttp3
,这是一个非常流行的 HTTP
库,可以简单、快速的实现 HTTP
调用。
安装 Okhttp3
的方式是在 pom.xml
文件中增加依赖:
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.1.0</version>
</dependency>
唯一的 <dependencies>
标签中,包含多个 <dependency>
标签,每一个 <dependency>
标签表示一个依赖库。书写时注意嵌套顺序哦。
pom.xml
文件的作用就是定义Java
项目需要用到(或者说依赖到)哪些库。
不必纠结
pom.xml
的含义及原理,在以后的高阶课程里会详细讲。当前会写依赖标签即可。
使用详解
使用 Okhttp3
完成页面请求,需要三大步骤:
- 实例化
OkHttpClient
。使用OkHttpClient okHttpClient = new OkHttpClient();
代码。 - 执行调用。
- 在执行调用之前,需要实例化一个
Request
对象,作用是定义请求的各种参数,Request request = new Request.Builder().url(url).build();
- 然后构建调用对象
Call call = okHttpClient.newCall(request);
- 最后执行调用,如果调用失败可能抛异常,所以必须抓取异常。
call.execute()
就是执行调用的代码。
- 在执行调用之前,需要实例化一个
call.execute()
返回的其实是一个执行的结果对象,调用对象的方法即可获取返回的字符串内容:call.execute().body().string();
这个过程你可以类比打电话:
- 拿出手机,相当于实例化Request对象,
- 拨号,相当于newCall()方法,这些都是前置操作,
- 每说一句话,相当于执行 execute() 方法,
- 听到对方说的话,就相当于获取返回结果 body().string()
演示的代码基本上都属于固定写法。
任何时候都不要忘记
pom.xml
文件添加依赖,以及代码中使用import
语句引入使用的类哦。
由于 Java
一切皆对象的理念,所以实际上代码量可能比大家想象的要大。
但是没关系,我们把调用的步骤封装在一个 getContent()
方法中,比较容易理解,也方便复用。大家不用太纠结,主要目标是熟练写出完整的代码。
关于输出结果
call.execute().body().string();
可以取得服务器返回的具体内容。在下一章我们会详细学习,这里大家知道用法即可。
我们在 console
中看到的大量的文本内容,这是给浏览器识别的内容,包含了很多无效的内容。所以很多时候,我们使用程序调用 API
,获取到需要的数据。
什么是 API
API 全称 Application Programming Interface,应用程序接口,API 一般是指一些预先定义的函数,目的是可以为开发人员快速访问某一程序,而无需了解和访问源码,或理解它内部工作机制的细节。
简单的讲,API 可以快速调用某个程序。
这在计算机里叫做接口,我们生活中也有很多接口,比如 U 盘可以储存信息,我们访问 U 盘,只需要把 U 盘插到电脑上就可以访问,插入的 USB 接口就是一个接口,我们不需要关心它是如何实现的。
又比如电视机上有很多接口,有的连话筒,有的连视频,我们只需要直接插上对应的线就可以实现相应的功能,并不关心它的具体机制。
如果大家想要了解关于更多 API
的知识,可以点击查看这个文档
调用 API
我们看一个查询 杭州市 天气的 API
:
https://api.seniverse.com/v3/weather/daily.json?key=SCYrvkytJze9qyzOh&location=杭州
把这个 URL 贴到浏览器,可以看到查询返回结果为:
{"results":[{"location":{"id":"WTMKQ069CCJ7","name":"杭州","country":"CN","path":"杭州,杭州,浙江,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"daily":[{"date":"2023-05-09","text_day":"晴","code_day":"0","text_night":"晴","code_night":"1","high":"20","low":"10","rainfall":"0.00","precip":"0.00","wind_direction":"东","wind_direction_degree":"90","wind_speed":"23.4","wind_scale":"4","humidity":"69"},{"date":"2023-05-10","text_day":"阴","code_day":"9","text_night":"小雨","code_night":"13","high":"22","low":"12","rainfall":"5.40","precip":"0.88","wind_direction":"东","wind_direction_degree":"90","wind_speed":"32.8","wind_scale":"5","humidity":"75"},{"date":"2023-05-11","text_day":"小雨","code_day":"13","text_night":"阴","code_night":"9","high":"20","low":"15","rainfall":"0.43","precip":"0.41","wind_direction":"无持续风向","wind_direction_degree":"","wind_speed":"3.0","wind_scale":"1","humidity":"80"}],"last_update":"2023-05-09T08:00:00+08:00"}]}
这一大段的内容,跟常见的精美的网页不同,全是数据,看到有些眼花缭乱。仔细看还是能看到 2023-05-09 杭州 的天气是 晴
数据基本上不是让人直接阅读的,是给前端程序使用的
关于前端编程在下一个阶段学到,目前不要纠结
所谓 API
,本质上就是一个 URL
。开头也是 http
(或https
),与精美的网页相比,内容有明显的区别。
API
返回的内容统称为数据
,关于数据的格式,我们以后会逐步讲到,这里先不赘述。
接下来我们就来动手实践吧!
网络编程的学习方法
学完本章,大家可能会有很多的疑问,特别是诸多代码看不懂。
这是 正常 的。
首先,网络编程与前面课程中的程序最大的不同,是用到了新的 程序开发包 。
这种程序开发包,由于不是 Java 官方出品的,而是其他公司或个人 开源 的,通常也叫 二方包 。
程序开发包,是为了更加简便的完成某些特定的功能,提升开发效率。
如果不用 Okhttp3 ,而是用 JDK 内置的类,也能完成相同的功能,但代码量会大很多。上一节 getContent() 方法大约有 18 行,如果不用 Okhttp3 代码量可能要再增加 3-4 倍。
除了第一次接触 Okhttp3 不习惯外,还有一个原因是大家对计算机的基础理论知识不熟悉,所以 Request、body() 这些都感觉懵懵懂懂。
计算机的基础理论知识,包括“计算机原理”、“计算机操作系统”、“计算机网络”等学校里的专业课程。这些课程学完以后,才能对本课程中涉及的代码有比较好的理解。
计算机网络的基础理论知识一般计算机专业会教,不是计算机专业的同学必须自学
不熟悉计算机网络知识就无法编程了吗?
答案是否定的: 当然可以编程 。
我们上节课已经用程序抓取了网页的源码和 API 的数据内容呢。
需要改变学习方法
学习开源技术的方法,与学习其它知识的方法,略有不同。
例如 Okhttp3 程序开发包的使用,我们可以先从粗到细的学习。就是说,我们 首先 要清晰的知道,这个技术解决了什么问题。
做什么
学过本课程,我们再看到一个新的 网址 ,必须能够想到使用 Okhttp3 获取其内容。
新网址无论是网页还是 API ,都要能举一反三,都能想到可以用 Okhttp3
怎么做
在第一节课中,已经把抓取过程的代码,封装在一个方法中:
public String getContent(String url) {
}
调用这个方法很简单,只要在参数中输入想抓取的网址,就会返回抓取的内容。
学习重点
记住:调用 getContent() 方法,即可抓取到网址的内容。就是说,首先要了解的是:知道什么代码可以解决什么问题、完成什么功能。
如果 getContent() 方法内的代码,某些细节看不懂,也 不要纠结 。因为,编程与考试不同的是,开发编程是允许查资料的。
就像我们都是先学会吃饭,即使不懂播种、打谷,也可以填饱肚子。
各位同学自己把完整的 getContent() 方法代码记在电脑上,例如印象笔记等各种笔记软件,甚至手写在纸质笔记本上,都可以。需要用的时候 copy 出来,即可完成功能。
当然,不要忘了两个配套步骤:添加依赖,不要遗漏 import 语句。
后面的章节
接下来的章节,根据不同的场景和条件,getContent() 方法的实现代码又会有一些不同。
那么大家学习后面的章节,就要特别注意区分,不同的代码适用于什么场景、能解决什么问题。
未来持续学习
待自己补充了计算机网络的理论知识,加上编程达到熟练程序以后,就可以回过头来研究 Okhttp3 的代码细节啦。
先预览一下 Okhttp3 的源代码:
现在看觉得很难,看不懂,没关系,随着技术能力的成长,以后会看得懂的。
我们目前要做的,是优化学习方法,分清主次、 抓重点
Get请求 - 有参数
上面我们练习了如何在程序中调用 API
获取结果。 很多情况下,API
调用需要参数,
例如,下列查询 IP
地址信息的 API
:
http://ip-api.com/json/?lang=zh-CN
我们只要把包含参数的完整的 URL
直接传入到方法中就可以了。
如果对 URL 的格式不熟悉,需要复习本课程第一章第二节哦
本节课没有新的知识点,希望大家强化编程训练,在编程的过程中加深理解 URL
和 API
POST表单数据
我们先来看一个故事:
话说灵剑派新弟子招募大会
升仙大会
在灵剑山下的灵溪镇召开,王陆跃跃欲试,也来到灵溪镇。镇上只有一家如家客栈,如果住不进去,就只能露宿街头了。
王陆来到如家客栈门口,只见一群人围在客栈门口,王陆很好奇,这是怎么回事呢?
此时老板娘来到客栈门前,开口说道:欲入住咱们如家客栈,除了需要登记姓名、年龄、籍贯外,最重要的,是必须持有准入券
,请持有准入券
者入内登记吧。
王陆微微一笑,嗖的一声从怀里掏出一张长方形纸片,只见白底绿纹上三个大字:准入券
,字上鲜红大印格外醒目。老板娘接过准入券笑吟吟做个手势:客官请。
提交数据至服务端进行增加、修改、删除等操作,都是
POST
操作。与王陆登记入住客栈类似,我们在网页上提交表单进行登录的场景,就是典型的POST
操作。
现在,我们回到计算机的世界,Java
是如何实现 POST
操作的呢?
post() 方法
Okhttp3
库也支持 POST
操作。我们前面学习的调用 API
属于 GET
操作。不同的是,POST
操作时,数据不是放在 URL
中的,而是放在表单中提交的。
所以程序实现需要构建一个 FormBody
表单对象,用于放置表单数据。核心代码如下:
Builder builder = new FormBody.Builder();
// 设置数据,第一个参数是数据名,第二个参数是数据值
builder.add("", "");
FormBody formBody = builder.build();Request request = new Request.Builder().url(url).post(formBody).build();
数据的写法是不是很眼熟呢?整体步骤跟请求 API
相似,不同的是,在构建 Request
对象时,使用 .post(formBody)
语句放入表单对象,就表示执行 POST
操作啦。
这段代码仍然属于固定写法,这里要学会熟练使用。
连写代码
这段代码出现了连写。
new Request.Builder().url(url).post(formBody).build();
大多数情况下 不推荐
使用连写(特别是新手不要使用连写)的方式。不用连写的方式应该写作:
Request.Builder build = new Request.Builder();
build = build.url(url);
build = build.addHeader("Referer", "http://www.taobao.com");
build = build.post(formBody);
Request request = build.build();
Request.Builder 表示 Builder 是 Request 的内部类。特殊的是需要通过 Request 类引用 Builder 类。
不懂内部类也没关系,不用纠结,重点是知道这段代码的功能就可以了。
关于内部类的知识点可以找 Java 书籍学习。
要完全理解 url header post 这些知识点,可能还需要 学校 里学过 《计算机原理》 、 《计算机网络》 课程,这里不用纠结。
可以 等学校里课程学完 后再来 复习 ,这里重点是学会 完成功能 。
即使不知道水稻是如何播种、如何收获的,但不妨碍大家吃饭
不连写的代码可能对新手更友好一点。但这段代码是发送 POST 请求专用的代码,不具备通用性,所以基于很多 大神、前辈 的编码风格,给大家展示简洁的连写风格。
请看下列代码演示 POST
登录的过程:
我们仍然把发送表单数据的过程,封装为 postConten
POST JSON 数据
在日常开发工作中,除了提交表单数据以外,也经常用到提交 JSON
数据。
跟表单数据提交方法一样,也是调用 post()
方法,只是参数不再使用 FormBody
对象,而是使用 RequestBody
示例
下列程序演示用 JSON
方法提交数据,注册一个新用户,数据包括:
数据名 | 数据值 |
---|---|
name | 张飞 |
secondName | 翼德 |
从 console 打印结果可以看到,服务器注册成功,并生了新用户的 id
号。
详解
实现 JSON
方式提交数据的步骤:
- 将数据转换成
JSON
格式的字符串,调用JSON.toJSONString()
方法即可。 - 创建
RequestBody
实例,注意需要指定提交的类型是application/json; charset=utf-8
。这里的utf-8
是API
规定的编码格式。此例子中,API
规定数据传输的编码格式是utf-8
- 编码属于另一个比较长的话题,属于课外知识了,有兴趣的同学可以看一下 码表的理解(ASCII,GBK,Unicode,UTF-8 等) - 构建
Request
实例对象时,调用.post(requestBody)
即表示使用JSON
的方式提交数据。
这些基本上都是固定写法,大家需要熟练应用。
附录
这篇我们用到了 JSON。对 JSON 及其使用不熟悉的同学,可以点击《JSON 与 FastJSON》文档