社区/学习指南/小程序云开发学习指南

网络 API

数据和文件是小程序开发非常重要的元素,在前面的章节里,数据和文件等的存储都是在小程序的页面进行渲染、或是页面间传递或与本地手机交互。这一节我们会来介绍数据、文件如何与网络 HTTP 进行数据、文件的对话,如何获取并上传网络数据和文件。

数据 API

小程序以及很多程序的 API 是预先就已经写好的函数,使我们不需要对底层有太多了解,只需要按照技术文档进行传递参数就能调用出非常复杂的功能。而还有一类 API 则侧重于把数据资源给开放出来,我们可以通过 HTTP 的方式来使用这些数据。

了解网络数据 API

复制以下链接地址,用浏览器打开,看看会返回什么结果:

//知乎日报的最新话题
https://news-at.zhihu.com/api/4/news/latest

//知乎日报某一个话题的内容
https://news-at.zhihu.com/api/4/news/9714883

//v2ex论坛的最新主题
https://www.v2ex.com/api/topics/latest.json

//CNode论坛的最新话题
https://cnodejs.org/api/v1/topics

以上所返回的数据类型都是 json 格式,相信大家应该比较熟悉了。那我们如何把以上数据渲染到我们的小程序页面上呢?

数据是一种资源,比如新闻资讯、电商商品、公众号文章、股市行情、空气质量和天气、地图、词典翻译、快递信息、书籍信息、音乐视频、财务公司信息等等这些都是数据,数据也是一种商品,一种服务,通常它的使用对象是开发者,有些免费,有些也会收取一定的费用,大家可以通过综合性API服务平台聚合API来对API服务有一个基础的了解。

练手 API 资源推荐

这里推荐几个程序员经常会拿来练手的 API 资源,你可以使用这些 API 来做网站、小程序、移动端(iOS、安卓)、桌面端,也可以用于各种框架比如 Vue、React、Flutter 等等,数据没变,只是解决方案不同。

  • 聚合 API:一个比较全面的综合性 API 服务平台
  • 即速 API:也是提供一些综合性的 API 服务
  • V2EX API:v2ex 论坛是很多程序员经常会光顾的综合性技术论坛
  • CNode API:Nodejs 交流论坛
  • 和风天气:含天气预报、空气质量、实况天气等数据
  • Github API:Github 是所有程序员都(必须)会使用的网站
  • 知乎日报 API:知乎日报 API 分析

各大公司的开发平台:比如微信开放平台提供了微信账号体系的接入,腾讯云 API 中心则提供了调用云资源的能力(包含服务器、物联网、人工智能等 API)、开源网站 Wordpress也提供 API 调用的服务,在 API 资源的开放方面,国外也做得比较领先(国外免费 API 列表)。而对于特定的数据资源,也可以通过爬虫等方式来自建。

渲染网络数据到页面

要渲染从 API 里获取到的数据,首先我们需要对 API 里的字段(属性)到底是干什么的要有一定的了解。比如知乎日报的 API 字段如下,这个可以从 API 相关的文档里了解到以及需要我们结合 Console.log 来对比了解。

比如 date : 日期;stories : 当日新闻;title : 新闻标题;images : 图像地址;id : url 与 share_url 中最后的数字为内容的 id;top_stories : 界面顶部轮播的显示内容,这些在做数据渲染前就需要有所了解。

获取网络数据

使用开发者工具新建一个 request 页面,然后在 request.js 里的 onLoad 生命周期函数里输入以下代码:

  onLoad: function (options) {
    wx.request({
      url: 'https://news-at.zhihu.com/api/4/news/latest', //知乎日报最新话题
      header: {
        'content-type': 'application/json' // 默认值
      },
      success(res) {
        console.log('网络请求成功之后获取到的数据',res)
        console.log('知乎日报最新话题',res.data)
      }
    })
  },

域名校验与白名单

编译之后,在控制台 Console 你会看到如下报错,你的域名不在域名白名单里面,这是因为小程序只可以跟指定的域名与进行网络通信。

request:fail url not in domain list

解决方法有两种,一是打开开发者工具工具栏右上角的详情,勾选不校验合法域名、业务域名、TLS 版本以及 HTTPS 证书;二是你可以去小程序的管理后台(注册小程序时的页面),点击开发–开发设置,在 request 合法域名处添加该域名(如果你不想把这个小程序发布上线,没有必要添加)。

res 对象和 res.data 对象

编译之后,在控制台 Console 就可以看到打印的 res 对象,以及 res 里的 data 对象。res.data 的数据正是我们使用浏览器打开链接所得到的 json 数据,结合我们之前学到的数据渲染方面的知识,相信大家应该对如何将数据渲染到页面就不会感到陌生了。

在打印的 res 对象有一些参数,比如 cookies、header、statusCode 这些是什么意思呢?我们可以来结合技术文档深入了解。

技术文档:wx.request 网络数据请求

  • statusCode:开发者服务器返回的 HTTP 状态码,也就是指示 HTTP 请求是否成功,其中 200 为请求成功,404 请求失败,更多状态码的知识可以查阅 MDN HTTP 响应代码
  • header:开发者服务器返回的 HTTP 消息头,其中 Content-Type 为服务器文档的 MIME 类型,API 的 MIME 类型通常为 "application/json; charset=UTF-8",建议服务器返回值使用 UTF-8 编码(如果你有服务器的话)。
  • wx.request 只能发起 HTTPS 请求,默认超时时间为 60s,最大并发限制为 10 个

小任务:把 request 的链接换成 v2ex、cnode 论坛的 API 链接以及知乎日报某一个话题的内容 API,看看是什么结果?你知道返回来的 json 数据的每一条属性代表的意思吗?

将数据渲染到页面

既然我们已经从知乎日报的 API 取得了数据,那渲染数据的方法以及如何实现跨页面渲染,在前面的章节我们已经就有所了解了。

简单的知乎日报首页

使用开发者工具在 request.wxml 里输入 weui 的列表样式(需要引入 weui 框架哦)

<view class="page__bd">
    <view class="weui-panel weui-panel_access">
        <view class="weui-panel__bd" wx:for="{{stories}}" wx:for-item="stories" wx:key="*item">
            <navigator url="" class="weui-media-box weui-media-box_appmsg" hover-class="weui-cell_active">
                <view class="weui-media-box__hd weui-media-box__hd_in-appmsg">
                    <image class="weui-media-box__thumb" mode="widthFix" src="{{stories.images[0]}}" sytle="height:auto"></image>
                </view>
                <view class="weui-media-box__bd weui-media-box__bd_in-appmsg">
                    <view class="weui-media-box__title">{{stories.title}}</view>
                </view>
            </navigator>
        </view>
    </view>
</view>

然后再在 request.js 的 data 里声明 date、stories、top_stories 的初始值(使用的变量和 API 的字段尽量保持一致,这样就不容易混乱)

  data: {
    date:"",
    stories:[],
    top_stories:[],
  },

在 onLoad 生命周期函数里将数据通过 setData 的方式给赋值给 data:

  onLoad: function (options) {
    let that=this
    wx.request({
      url: 'https://news-at.zhihu.com/api/4/news/latest',
      header: {
        'content-type': 'application/json'
      },
      success(res) {
        let date=res.data.date
        let stories=res.data.stories
        let top_stories = res.data.top_stories
        that.setData({
          date,stories,top_stories
        })
      }
    })
  },

编译之后,我们就能看到知乎日报的数据就渲染在页面上了。

小任务: top_stories 是界面顶部轮播的显示内容,制作一个swiper轮播,将top_stories里的内容渲染到轮播上。

打开开发者工具调试工具栏的AppData标签页,就能看到从网络API里获取到的数据。也可以在此处编辑数据,并及时地反馈到界面上。如果AppData里有数据,可以确认页面已经取得res里的data数据,如果数据没有渲染到页面,说明列表渲染可能有误。通过这种方式可以诊断页面渲染问题所在。

详情页数据渲染

前面我们获取的只是知乎的最新文章列表,那文章里面的内容呢?通过 API 文档以及我们通过链接访问的结果来看,我们只需要取得了文章的 ID,就能从 API 里获取到文章的详情页内容:

https://news-at.zhihu.com/api/4/news/9714883  //9714883是文章的ID

使用开发者工具新建一个 story 页面,然后在 story.wxml 里输入以下代码:

<view class="page__bd">
    <view class="weui-article">
        <view class="weui-article__h1">{{title}}</view>
        <view class="weui-article__section">
            <view class="weui-article__section">
                <view class="weui-article__p">
                    <image class="weui-article__img" src="{{image}}" mode="widthFix" style="width:100%" />
                 </view>
                 <view class="weui-article__p">
                      {{body}}
                </view>
                <view class="weui-article__p">
                        知乎链接:{{share_url}}
                </view>
            </view>
        </view>
    </view>
</view>

然后再在 request.js 的 data 里声明 title、body、image、share_url 的初始值:

data: {
    title:"",
    body:"",
    image:"",
    share_url:"",
  },

在 onLoad 生命周期函数里调用 wx.request 获取文章详情页的数据,并通过 setData 的方式给赋值给 data:

  onLoad: function (options) {
    let stories_id=9714883
    let that = this
    wx.request({
      url: 'https://news-at.zhihu.com/api/4/news/'+stories_id,
      header: {
        'content-type': 'application/json'
      },
      success(res) {
        let title = res.data.title
        let body=res.data.body
        let image=res.data.image
        let share_url=res.data.share_url
        that.setData({
          title,body,image,share_url
        })
      }
    })

编译之后,发现数据虽然渲染出来了,但是存在“乱码”(是 HTML 标签),那这个要如何处理呢?这个就涉及到小程序的富文本解析了。

HTML 标签解析 rich-text

只需要将富文本对象放在 rich-text 的 nodes 里,就能将富文本解析出来了,比如将上面的{{body}}替换成以下代码。

<rich-text nodes="{{body}}"></rich-text>
小程序富文本解析的方案还有:Comi ,腾讯 Omi 团队开发的小程序代码高亮和 markdown 渲染组件,Github地址,具体效果可以在微信小程序里搜索omiCloud;以及wxPrase,微信小程序富文本解析自定义组件,支持HTML及markdown解析,Github地址,当你遇到更加复杂的富文本解析时,可以来深入了解。

跨页面数据渲染

上面我们只是渲染了单篇文章的详情页,那如何点击文章列表就能渲染与之相应的文章详情页呢?这就回到了我们之前学过的跨页面数据渲染。

首先把 request 页面置于首页,然后再给 request.wxml 里的 navigator 组件的链接上携带文章的 id:

url="/pages/story/story?id={{stories.id}}"

当点击 request 页面的链接时,链接携带的数据就会传到 story 页面的生命周期函数 onLoad 的 options 对象里,将 options 里的 id,赋值给 stories_id,也就是将文章 id 9714883 修改为 options.id

let stories_id=options.id

这样再来点击 request 页面的链接,不同的链接就会渲染不同的文章详情。

解构赋值

解构赋值也就是从数组 Array 和对象 Object 中提取值,按照对照的位置,对变量进行赋值。比如上面的变量声明,为了能够与 API 里的数据字段一一对应,我们会声明很多变量,知乎日报的 API 还算比较少的,多了就比较复杂了。

let title = res.data.title
let body=res.data.body
let image=res.data.image
let share_url=res.data.share_url

这时可以简写成:

let { title, body, image, share_url}=res.data

历史上的今天

知乎日报的 API 是比较开放的,并不需要我们去注册 API 服务就能获取到这些数据,但是大多数情况下,API 是商品服务,需要我们注册,那需要注册的 API 和开放的 API 有什么不同呢?

注册历史上的今天的服务

注册聚合 API并认证,认证之后可以申请开通历史上的今天、图书电商数据等免费的 API 服务,并找到你的与之对应的 AppKey。

替换下面链接你的历史上的今天对应的 key(直接输 AppKey 就行),然后在浏览器打开链接(下面这个是 1.0 版)

http://api.juheapi.com/japi/toh?month=9&day=15&key=你的历史上的今天对应的key

也可以选择事件列表的 2.0 版(为了讲解方便,下面以 1.0 版本为主)

http://v.juhe.cn/todayOnhistory/queryEvent.php?date=9/15&key=你的历史上的今天对应的key

key 的存放

通常我们会把拿到的 key 放在 app.js 的 globalData 里,或者在小程序里新建一个 config.js,方便以后全局调用,而不是把 key 直接写在页面里。

方法一:写在 app.js 里的 globalData,或者新建一个 keyData 对象,只要达到全局调用的目的都可以,以 globalData 为例

  globalData: {
    juheKey:"366444.......00ff", //聚合AppKey
  },

这种方式调用时首先在页面的 js 文件里、Page()函数的前面使用

const app=getApp()

之后就可以使用 app.globalData.juheKey 来调用它了。

方法二:也可以在小程序的根目录或者 utils 文件夹新建一个 config.js,然后结合前面模块化的知识,写入以下代码:

module.exports = {
  juheKey:"366444.......00ff", //聚合AppKey
}

这种方式调用时我们需要先在页面的 Page()函数前面引入模块化文件

const key = require('../../utils/config.js')

然后就可以使用 key.juheKey 调用它了。

将一些通用的数据、函数单独拿出来存放在globalData里或进行模块化,是在实际开发中会经常使用到的一种方法,它可以让数据、函数更容易管理以及可以重复利用,使得代码更加精简。

wx.request 请求数据

使用开发者工具新建一个 apidata 页面,然后在 apidata.js 的 Page()函数前面输入以下代码:

const app=getApp()
const now = new Date();
const month = now.getMonth()+1 //月份需要+1
const day = now.getDate()

然后再在生命周期函数 onLoad 里输入 wx.request 数据请求:

  onLoad: function (options) {
    wx.request({
      url: 'http://api.juheapi.com/japi/toh',
      data: {
        month: month,
        day: day,
        key: app.globalData.juheKey,
      },
      header: {
        'content-type': 'application/json'
      },
      success(res) {
        console.log(res.data)
      }
    })
  },

wx.request 里的 data 就是要传入的参数,我们把 month、day、key 传入到请求的链接里。它等价于以下链接(注意把 data 里的属性值,以免传两次参数)

url: "http://api.juheapi.com/japi/toh?" + "month=" + month + "&day=" + day + "&key=" + app.globalData.juheKey,

模板字符串

要将多个字符串连接起来,可以使用加号+来用作字符串的拼接,如果变量比较多,是不是很麻烦?我们还可以使用模板字符串,模板字符串使用反引号 ``来表示(在电脑键盘 esc 按键下面)。要在模板字符串中嵌入变量,需要将变量名写在 ${}之中,比如上面的链接也可以写成:

url: `http://api.juheapi.com/japi/toh?month=${month}&day=${day}&key=${app.globalData.juheKey}`,

在控制台我们就可以看到获取到的 res.data 数据,至于如何渲染到页面,这里就不多介绍了。

天气 API

注册和风天气,并在控制台的应用管理新建一个应用,获取到该应用的 key,按照上面的方法将 key 添加到 globalData 里:

  globalData: {
    heweatherKey:"732c.........0b", //和风天气key
  }

通过技术文档我们可以了解到免费版和风天气 API 的必备字段为 weather-type(根据不同的值可以取得不同的数据)和请求参数(其中 location 为必备参数)

技术文档:和风常规天气数据 API

也就是我们可以通过链接可以获取到数据,注意 now 在问号?的前面,也就是它不是请求的参数,location 和 key 才是。

https://free-api.heweather.net/s6/weather/now?location=beijing&key=你的key

然后再在 apidata.js Page()的 data 里初始化声明 weathertype(属性名最好不要有连接符-)和 location:

  data: {
    weathertype:"now",
    location:"beijing"  //location的写法有很多种,具体可以参考技术文档
  },

然后再在生命周期函数里添加 wx.request 请求(onLoad 里可以写多个 wx.request 请求)

    const weathertype=this.data.weathertype
    wx.request({
      url: `https://free-api.heweather.net/s6/weather/${weathertype}`,
      data: {
        location: that.data.location,
        key: app.globalData.heweatherKey,
      },
      header: {
        'content-type': 'application/json'
      },
      success(res) {
        console.log(res.data)
      }
    })
  },

在控制台就能看到请求到的 res.data 了。如果你想点击按钮切换不同城市以及不同的天气数据类型,结合前面所学的知识,我们只需要通过事件处理函数调用 setData 修改 weathertype 和 location 即可。

encodeURI 与 decodeURI

在浏览网页的时候我们经常看到汉字或一些字符变成了一个“乱码”,原因就在于链接进行了编码处理。encodeURI() 函数可把字符串作为 URI 进行编码,而 decodeURI()函数则可以进行解码。

在开发者工具的控制台里输入以下代码

console.log(encodeURI("北京"))
console.log(decodeURI("%e9%85%92%e5%ba%97"))
console.log(decodeURI("https://hackwork.org/handbook/python/174/%e5%86%99%e5%87%ba%e7%ac%ac%e4%b8%80%e8%a1%8cpython%e4%bb%a3%e7%a0%81/"))

腾讯地图 LBS

如果想在小程序中调用地图的 POI 检索(POI,即兴趣点 Point of Interest,区域内搜索酒店、学校、ATM 等)、 关键词输入提示、地址解析、逆地址解析、行政区划、距离计算、路径规划等数据服务,这时候就需要使用到地图类相关的 API。

地图 API:腾讯 LBS 位置服务

注册账号获取 Key

首先在注册后登录,点击控制台 —key 管理—创建新密钥,然后取得 key,key 的格式类似于“43UBZ-*-*-*-*-HTBIA”。

然后点击当前 Key 的设置,启动产品里勾选微信小程序和 WebServiceAPI 里的签名校验,获取到地图的 Secret key。这两种 API 的调用方式,小程序都支持。

然后将地图的两个 key,写入到 globalData 里

  globalData: {
    mapKey:"43UBZ-*****-IITUH-*****-2M723-******",//你的key
    mapSecretKey:"spZwWz**********Xh20uW", //你的Secret key
  }

md5 加密算法

WebServiceAPI Key 配置中签名校验里提到我们使用 WebServiceAPI 的方法需要对请求路径+”?”+请求参数+SK 进行拼接,并计算拼接后字符串 md5 值,即为签名(sig)。MD5 是计算机安全领域广泛使用到的一种加密算法,主要用于确保消息传输的完整一致。

md5 依赖:md5 开源项目下载链接

解压之后,将 js 文件夹里的 md5.min.js 复制粘贴到小程序 utils 文件夹下。然后再在 Page()前面引入这个文件

const md5 = require('../../utils/md5.min.js')

坐标逆解析

坐标的逆解析就是坐标(latitude,longitude)转化为详细的地址名。

技术文档:坐标的逆地址解析

再在 apidata.js Page()的 data 里初始化声明 latitude,longitude,比如我们用腾讯大厦的经纬度值:

  data: {
    latitude:"22.540503",
    longitude: "113.934528",
  },

然后在 onLoad 函数里调用 wx.request 发起 HTTPS 网络请求

  onLoad: function (options) {
   let that=this
    const { latitude, longitude } = that.data
    const { mapKey, mapSecretKey}=app.globalData
    let SIG = md5("/ws/geocoder/v1?key=" + mapKey + "&location=" + latitude + "," + longitude + mapSecretKey)
    wx.request({
      url: 'https://apis.map.qq.com/ws/geocoder/v1',
      data: {
        key: mapKey,
        location: `${latitude},${longitude}`,
        sig: SIG
      },
      header: {
        'content-type': 'application/json'
      },
      success(res) {
        console.log(res.data)
      }
    })
  },

在控制台 Console 就可以看到当前坐标(latitude,longitude)逆解析出来的详细信息。

小程序使用腾讯地图位置服务,还有一种更加简单的方法,具体可以阅读《微信小程序:个性地图使用指南》

本文出自 李东bbsky