1.1. HTTP 数据请求
什么是HTTP数据请求:
(鸿蒙)应用软件可以通过(鸿蒙)系统内置的 http 模块,通过 HTTP 协议和服务器进行通讯
核心概念:
- 什么是服务器?
-
- 在网络上提供服务器的一台电脑,比如提供数据服务
- 什么是 http 模块?
-
- 鸿蒙内置的一个模块,可以通过 【HTTP 协议】和【服务器】进行通信
- HTTP协议?
-
- 规定了客户端和服务器返回的内容【格式】
- 在通讯的时候需要按照格式发送内容,才可以进行通讯
1.2. http模块基本用法
基本用法:
// 1. 导入
//import http from '@ohos.net.http'
import { http } from '@kit.NetworkKit'
// 2. 创建请求对象
const req = http.createHttp()
// 3. 根据提供好的 地址发送请求,并在 then 中获取服务器响应的内容
req.request('请求地址url')
.then((res: http.HttpResponse) => {
AlertDialog.show({ message: JSON.stringify(res) })
})
注意:
- 预览器 和 模拟器 以及真机都可以发送请求
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
}
}
发送请求:
import http from '@ohos.net.http'
import { http } from '@kit.NetworkKit'
@Entry
@Component
struct Notebook_use {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(20)
Button('点击发起网络请求')
.onClick(() => {
const req = http.createHttp()
req.request('https://api-vue-base.itheima.net/api/joke')
.then((res: http.HttpResponse) => {
// AlertDialog.show({ message: JSON.stringify(res) })
this.message = res.result.toString()
})
})
}
.width('100%')
}
.height('100%')
}
}
json
2.1 基本概念
什么是JSON?
JSON 是一种按照 JavaScript 对象语法的数据格式,虽然它是基于 JavaScript 语法,但它独立于 JavaScript,许多【程序环境】能够读取(解读)和生成 JSON。
JSON的作用?
JSON是一个字符串,常用于存储和传递数据,开发中常见于 2 个地方:
- 传递数据:
- 配置文件(xxx.json,xxx.json5)
语法规则:
- 是一个字符串(配置文件中两边可以不写引号)
- 属性名用双引号包裹,
- 属性值如果是字符串也必须用双引号包裹
- 对象{},数组[]
const jsonObj='{"name":"jack","age":18}'
const arr = '["你好","西兰花炒蛋"]'
2.2. JSON字符串转换
如果要在 JSON 和对象之间转换,就需要用到对应api 啦:(数组也是对象)
JSON.stringify(对象)// 转为 JSON
JSON.parse(JSON) // 转为 对象,需要设置类型(通过变量类型或 as)
interface Person{
name:string
age:number
}
// JSON.parse
const jsonObj='{"name":"jack","age":18}'
const obj:Person = JSON.parse(jsonObj) as Person
const obj2 = JSON.parse(jsonObj) as Person
const jsonArr = '["你好","西兰花炒蛋"]'
const arr:string[] = JSON.parse(jsonArr)
// JSON.stringify
const p:Person={
name:'rose',
age:20
}
AlertDialog.show({
message:JSON.stringify(p)
})
易错点:
- url 地址不能有空格
- 写类型的时候,不能出现属性名不一致的情况
2.3url查询参数
URL查询参数是提供给网络服务器的额外参数。这些参数是用 & 符号分隔的键/值对列表。在返回资源之前,Web 服务器可以使用这些参数来执行额外的操作。每个 Web 服务器都有自己关于参数的规则,唯一可靠的方式来知道特定 Web 服务器是否处理参数是通过询问 Web 服务器所有者
简而言之: 携带给服务器额外信息,让服务器返回我想要的某一部分数据而不是全部数据
实际开发时,服务器的所有者会提供 URL 查询参数的信息,比如
地址: https://api-vue-base.itheima.net/api/joke/list
根据查询参数获取若干条随机笑话
参数名: num
说明: 传递数量即可,比如 5
案例实现:
// import http from '@ohos.net.http';
import { http } from '@kit.NetworkKit';
const req = http.createHttp()
// 定义好了接受服务器返回的数据类型
interface iRes {
msg: string
code: number
data: string[]
}
@Entry
@Component
struct Day01_03_QueryParams {
@State pname: string = '湖南省';
@State jokeNum: string = '' // 获取笑话的条数
@State jokes: string[] = [] // 存储笑话的数组
@State cities: string[] = []
build() {
Column() {
// 开心一笑
Column({ space: 10 }) {
Text('开心一笑')
.fontSize(30)
TextInput({ placeholder: '输入笑话条数', text: $$this.jokeNum })
.type(InputType.Number)
// onSubmit表示用户在文本框中输入内容之后回车就会触发这个事件
.onSubmit(() => {
// 目标:用户在文本框中输入数量之后,回车就应该请求url地址
// https://api-vue-base.itheima.net/api/joke/list?num=用户输入的数量
req.request(`https://api-vue-base.itheima.net/api/joke/list?num=${this.jokeNum}`)
.then(res => {
// 将服务器返回来的数据转成iRes类型的对象
let resObj: iRes = JSON.parse(res.result.toString())
this.jokes = resObj.data
})
})
ForEach(this.jokes, (joke: string) => {
Text(joke)
})
}
.layoutWeight(1)
.width('100%')
.padding(10)
}
}
请求方法和数据提交
- GET请求方法是HTTP模块的默认请求方法
- 向服务器发送数据我们常用的方式是POST请求方法(需要显示指定)
3.1:POST请求
POST请求语法:
const req = http.createHttp()
req.request('请求地址', {
method: http.RequestMethod.POST, // 通过枚举的方式设置请求方法,如果是 get 可以省略
// 向服务器提交数据写法1:传对象(需要配合header头参数,后面再说)
extraData: {}
// 向服务器提交数据写法2(此处先用写法2)传字符串 写成 'key=value&key2=value2'......
extraData:'key=value&key2=value2'
})
post请求的使用:
import { http } from '@kit.NetworkKit'
@Entry
@Component
struct Day01_05_SubmitData {
@State username: string = 'test3212'
@State password: string = '123456'build() {
Column({ space: 15 }) {
Text('请求方法和数据提交')
.fontSize(30)
.fontWeight(FontWeight.Bold)
TextInput({ text: $$this.username, placeholder: '用户名' })
TextInput({ text: $$this.password, placeholder: '密码' })
.type(InputType.Password)Button('提交数据')
.width('100%')
.onClick(() => {
// 获取用户名和密码 利用http模块将这2个数据提交给服务器完成注册功能
/*
* 1. 导入http模块
* 2. 创建对象请求url
* 3. 处理服务器返回来的数据
* */const req = http.createHttp()
req.request('http://hmajax.itheima.net/api/register', {
method: http.RequestMethod.POST, //请求方法是POST
extraData: `username=${this.username}&password=${this.password}` //向服务器提交的参数
})
.then(res => {
AlertDialog.show({ message: JSON.stringify(res.result, null, 2) })
})
})
}
.width('100%')
.height('100%')
.padding(20)
}
}
HTTP协议
请求报文的组成部分:
- 请求行:请求方法,URL,协议(第一行)
- 请求头:以键值对的格式携带的附加信息,比如:Content-Type(第二行开始到空行)
- 空行:分隔请求头,空行之后的是发送给服务器的资源(空行)
- 请求体:发送的资源(空行之后)
响应体
- 响应行(状态行):协议、HTTP响应状态码、状态信息(第一行)
- 响应头:以键值对的格式携带的附加信息,比如:Content-Type(第一行到空行)
- 空行:分隔响应头,空行之后的是服务器返回的资源(空行)
- 响应体:返回的资源(空行之后)
咱们一般需要关注,响应行,响应体即可
状态码:我们可以根据状态码来反映请求是否完成
请求库-axios
4.1 下载axios
# 安装
ohpm i @ohos/axios
# 卸载
ohpm uninstall @ohos/axios
4.2 axios完成POST请求
语法:
// 1. 导入axios
// AxiosError:异常时的数据类型
// 正常时的数据类型AxiosResponse 是一个泛型类型
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
// 2. 创建axios的对象实例
const req = axios.create()
// 3. 发送POST请求,并提交数据给服务器
let res:AxiosResponse<响应数据类型> =
await req.request<响应数据类型(可以写null), AxiosResponse<响应数据类型>, 请求体数据类型>({
method: 'POST', // 请求方法
url: 'https://hmajax.itheima.net/api/login', //服务器url地址
data: { // 请求体数据
username: 'jack123456',
password: '12345678'
}
})
// post使用1. 导入axios
import axios, { AxiosResponse } from '@ohos/axios'export interface iRequestBody {
/**
* 密码,最少6位
*/
password: string;/**
* 用户名,最少8位,中英文和数字组成,
*/
username: string;
}export interface iResponse {
/**
* 业务状态码,10000成功, 10004-账号/密码未携带
*/
code: number;/**
* 响应消息
*/
message: string;
}@Entry
@Component
struct Index {
build() {
Column() {
Button('axios发送post请求')
.onClick(async () => {
// 2. 创建请求对象实例
const req = axios.create()// 3. 利用req.request方法发送post请求
try {
let res: AxiosResponse<iResponse> =
// 三个泛型参数解释:
/*
* 第一个参数:表示响应类型 (直接写null)
* 第二个参数:表示响应体的类型 AxiosResponse<写接口返回的数据interface>
* 第三个参数:表示请求体的类型 ,写接口的请求body的interface
* */
await req.request<null, AxiosResponse<iResponse>, iRequestBody>({
method: 'POST',
url: 'https://hmajax.itheima.net/api/login',
// data的类型是reqeust第三个泛型参数的类型
data: {
username: 'jack123456',
password: '12345678'
}
})
AlertDialog.show({ message: JSON.stringify(res.data.message, null, 2) })
} catch (err) {
AlertDialog.show({ message: JSON.stringify(err, null, 2) })
}
})}
.height('100%')
.width('100%')
}
}
4.3 axios完成GET请求 (无参和有参)
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
export interface ApifoxModel {
/**
* 响应数据
*/
data: Datum[];/**
* 响应消息
*/
message: string;
}export interface Datum {
/**
* 顶级分类id
*/
id: string;/**
* 顶级分类名字
*/
name: string;/**
* 顶级分类图片
*/
picture: string;
}@Entry
@Component
struct Index {
build() {
Column() {Button('axios.get')
.onClick(async () => {
// 1. 创建请求实例
const req = axios.create()// 2. async 和 await方式发送get请求(不带参数)
try{
let res: AxiosResponse<ApifoxModel> = await req.request({
method: 'get',
url: 'https://hmajax.itheima.net/api/category/top'
})
AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
} catch (err) {
let errObj: AxiosError = err
AlertDialog.show({ message: '出错了:' + JSON.stringify(errObj.message, null, 2) })
}// 3. .then().catch()方式发送请求(不带参数)
// req.request({
// method: 'get',
// url: 'https://hmajax.itheima.net/api/category/top1'
// })
// .then((res: AxiosResponse<ApifoxModel>) => {
// AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
// })
// .catch((err: AxiosError) => {
// AlertDialog.show({ message: '出错了:' + JSON.stringify(err, null, 2) })
// })})
}
.height('100%')
.width('100%')}
}
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
export interface ApifoxModel {
/**
* 响应数据
*/
data: Data;
/**
* 响应消息
*/
message: string;
}/**
* 响应数据
*/
export interface Data {
/**
* 顶级分类下属二级分类数组
*/
children: Child[];
/**
* 顶级分类id
*/
id: string;
/**
* 顶级分类名字
*/
name: string;
/**
* 顶级分类图片
*/
picture: string;
}export interface Child {
/**
* 二级分类id
*/
id: string;
/**
* 二级分类名字
*/
name: string;
/**
* 二级分类图片
*/
picture: string;
}@Entry
@Component
struct Index {
build() {
Column() {Button('axios.get')
.onClick(async () => {
// 1. 创建请求实例
const req = axios.create()// 2. async 和 await方式发送get请求(带参数)
try{
let res: AxiosResponse<ApifoxModel> = await req.request({
method: 'get',
url: 'https://hmajax.itheima.net/api/category/sub',
params:{
id:'1005000'
}
})
AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
} catch (err) {
let errObj: AxiosError = err
AlertDialog.show({ message: '出错了:' + JSON.stringify(errObj.message, null, 2) })
}// 3. .then().catch()方式发送请求(带参数)
// req.request({
// method: 'get',
// url: 'https://hmajax.itheima.net/api/category/sub',
// params:{
// id:'1005000'
// }
// })
// .then((res: AxiosResponse<ApifoxModel>) => {
// AlertDialog.show({ message: JSON.stringify(res.data, null, 2) })
// })
// .catch((err: AxiosError) => {
// AlertDialog.show({ message: '出错了:' + JSON.stringify(err, null, 2) })
// })})
}
.height('100%')
.width('100%')}
}
3.2. axios基地址配置
// 基于配置,返回一个 axios 的实例,如果多个页面使用同一个基地址可以将其放入一个新文件中并导出提高复用性和维护性
const req = axios.create({
// 基地址,后续请求的时候这部分可以省略
baseURL:'https://hmajax.itheima.net'
})
// get 请求 直接写 url 即可
let res: AxiosResponse<ApifoxModel> = await req.request({
method: 'get',
url: '/api/category/top'
})
AlertDialog.show({ message: JSON.stringify(res) })