本文共 4430 字,大约阅读时间需要 14 分钟。
忙带懒,好久没有更新文章了(其实主要是想留给你们一些消化前面文章知识点的时间,哈哈哈)。
我们在前文 中,初步学习了如何使用Node.js服务端框架Express来编写后端服务,并基于Express,对我们先前的的代码进行了一次重构。如果你是个初学者的话,相信通过阅读和实践前面的几篇文章,你已经能开始自己写一些代码了,并能对一个程序的各个组成部分建立起更加清晰直观的认识,知道什么是客户端,什么是服务端。
今天,在这个基础上,我想拓展一下你们对于客户端的理解。如果我没猜错的话,应该很多人都会把网页,移动app,桌面程序等用户直接可以操作的部分,当做客户端。从一个程序的用户角度来说,这种说法是没错的。不过,从程序本身来说的话,客户端的定义就会广泛许多,来看下图:
在该图示意的系统中,我们有多个后端服务(在一个实际的软件系统中,这个是非常常见的),这些后端服务之间也会互相的进行调用;后端服务也会调用其他第三方提供的服务。这种情况下,我们会把提供服务的叫做服务端,调用服务的叫做客户端。因此,该图中的界面UI
、后端服务1
、后端服务2
在其有限的范围内,都可以被称作客户端:界面UI
是后端服务1
和后端服务2
的客户端;后端服务1
是后端服务2
和第三方服务1
的客户端,以此类推。
客户端调用服务端的时候,需要遵循事先的约定,也就是我们常说的协议。到目前为止,我们开发的服务都是基于HTTP协议,所以在客户端我们也都需要使用HTTP协议来发起调用。
在浏览器中,我们通常可以通过<form>
表单或XMLHttpRequest
的来调用服务端的HTTP服务。
我们先来看一下使用<form>
,如何来调用我们之前写的计算器后端服务/calc
:
在我们的html代码会像是这样:
在这个表单中,<form>
标签上的action
属性设置为目标调用的服务路径,method
设置为调用所使用的HTTP方法。然后在<form>
表单下的<input>
和<select>
都需要设置上name
属性,它们会被用做调用服务的参数名,传递到服务端。
使用XMLHttpRequest
调用的方式,也就是我们耳熟能详的AJAX
,其实在我们之前的计算器示例代码中就已经使用了:
function calc() { // 获取id为num1的输入框 var num1El = document.getElementById('num1'); // 从num1输入框获取文字内容并转换成数字类型 var num1 = parseFloat(num1El.value); // 获取id为num2的输入框 var num2El = document.getElementById('num2'); // 从num2输入框获取文字内容并转换成数字类型 var num2 = parseFloat(num2El.value); // 获取id为operator的下拉框 var operatorEl = document.getElementById('operator'); // 从下拉框获取当前选中的内容 var operator = operatorEl.value; // 后端服务的地址 var requestUrl = '/calc'; // 要发送到后端的数据 var requestParams = 'num1=' + num1 + '&num2=' + num2 + '&operator=' + encodeURIComponent(operator); // 把上面的地址和数据拼到一起来 var url = requestUrl + '?' + requestParams; // 创建一个XMLHttpRequest对象,通过它来和后端服务进行通信交互 var xhr = new XMLHttpRequest(); // 设置当后端请求产生反馈后的处理 xhr.onreadystatechange = function () { if (xhr.readyState === 4) { // 成功 if (xhr.status === 200) { alert('计算结果是:' + xhr.responseText); } // 失败 else { alert('请求服务器失败'); } } }; // 开始发送请求 xhr.open('GET', url, true); xhr.send(null);}
这个代码中,直接使用了XMLHttpRequest
的API来进行服务的调用,没有考虑到在不同浏览器上的兼容问题,代码也比较冗长,在现在的实际开发中,我们已经不太会采用了,取而代之的是使用经过良好封装的开源库,如, 等。
我们来看一下使用这些开源库的API是如何来实现等价的服务调用功能的。
这是使用jQuery改写成的版本:
function calc() { $.ajax({ method: 'get', url: '/calc', data: { num1: parseFloat($('#num1').val()), num2: parseFloat($('#num2').val()), operator: $('#operator').val() } }).then(function (result) { alert('计算结果是:' + result); }).catch(function () { alert('请求服务器失败'); });}
而这是使用axios改写成的版本:
function calc() { axios({ method: 'get', url: '/calc', params: { num1: parseFloat(document.getElementById('num1').value), num2: parseFloat(document.getElementById('num2').value), operator: document.getElementById('operator').value } }).then(function (response) { alert('计算结果是:' + response.data); }).catch(function () { alert('请求服务器失败'); });}
可以看到,使用jQuery或axios改写的版本,从代码上来说,要比使用原始XMLHttpRequest API的版本要简洁,而且都支持Promise,所以在写异步流程控制代码方面,显得要方便很多。另外,这些库都考虑到了浏览器之间的兼容问题,所以同样的代码在不同的浏览器上运行,都没什么问题。
看完浏览器端的调用,我们再转到服务端来。在Node.js的服务端代码中,如果要发起对其他HTTP服务的调用的话,Node.js提供了一个叫做http
的模块。
我们在Node.js中去调用一个天气预报的API,代码看起来会是这样子的:
const http = require('http');http.get('http://www.weather.com.cn/data/sk/101190401.html', function (req, res) { let result = ''; req.on('data', function (data) { result += data; }); req.on('end', function () { console.info(result); });});
执行这段代码,可以得到类似如下的结果:
{"weatherinfo":{"city":"苏州","cityid":"101190401","temp":"17","WD":"东南风","WS":"2级","SD":"44%","WSE":"2","time":"17:05","isRadar":"0","Radar":"","njd":"暂无实况","qy":"1017","rain":"0"}}
是不是也挺简单的?这是Node.js自带的模块,其实还有很多第三方的开源库可以用,比如request
,或者是前面提到过的axios
(它同时支持浏览器端和Node.js端)。作为全栈JS开发,我们非常希望代码复用性强,风格统一,因此,我推荐无论在浏览器端还是Node.js端,我们都可以统一使用axios
来编写HTTP服务调用代码。
所以,我们继续来用axios改写一下上面的代码:
记得先安装一下axios模块:
npm install axios
const axios = require('axios');axios({ method: 'get', url: 'http://www.weather.com.cn/data/sk/101190401.html'}).then(function (response) { console.log(response.data);}).catch(function () { console.log('请求服务器失败');});
通过上述简单的例子,希望能让你触类旁通,然后通过自己的深入学习了解,完全掌握客户端和服务端的概念,以及两者之间的内在联系。
新的一年,学习创造新的价值。
欢迎关注一斤代码的系列课程
转载地址:http://bjxca.baihongyu.com/