- 作者:老汪软件技巧
- 发表时间:2024-12-29 15:04
- 浏览量:
前言
作为前端小白,经常会遇到这个问题:接口文档我看懂了,那怎么写代码呢?
上篇文章借助 Apifox 这个工具,介绍了如何看懂接口文档以及如何调试。本篇文章,就来介绍,如何写访问接口的代码
# 面向前端小白,Apifox简单使用
浏览器直接访问
讲具体的代码之前,先讲讲浏览器访问。
其实,对于 GET 请求方式的接口,我们可以直接在浏览器的搜索栏里输入接口地址,敲回车,页面上就可以看到服务器返回的内容。比如:
https://www.baidu.com
这是一个百度的网址,也是一个百度的接口。在浏览器中输入这个地址,然后敲回车,我们就能看见百度的搜索官网了。
这其中的过程是,我们通过浏览器访问这个接口,百度服务器收到访问的请求后,就会返回对应的数据,浏览器拿到这个数据,会对其进行解析。浏览器发现这个数据是 html,然后才对其进行渲染。
接口可以返回任何东西,可以是一个 html,也可以是一张图片,也可以是一段文本,也可以是一个 json 类型的文本
接口就是一个 URL,以正确的方式,访问这个 URL,我们就能得到服务器返回的数据
下面这个接口返回图片:
const url = 'https://p6-passport.byteacctimg.com/img/user-avatar/f98d9dd3d0cd8e6787115b1511f99fd5~200x200.awebp'
在浏览器访问这个链接,你能看到服务器返回的图片:
/img/user-av…
下面这个接口直接返回 json 文本:
数据很多,看不太出来。点下美观输出:
很明显,返回的内容就是一个 json 文本
Fetch
在 JS 中,提供了原生的 API--fetch,可以直接使用它访问接口:
我们先试着访问那个图片:
const url =
'https://p6-passport.byteacctimg.com/img/user-avatar/f98d9dd3d0cd8e6787115b1511f99fd5~200x200.awebp';
// fetch可以直接使用,不用下载任何第三方库
fetch(url)
.then(res=>res.blob())
.then((res) => {
console.log(res);
});
将上面的代码,放在一个 html 文件的 script 标签中:
在浏览器中打开这个文件,然后看下控制台:
请求成功。可以看到返回的数据是 image 类型的
下面试试访问本地接口的例子,用 fetch 请求:3000/task?user_id=1:
const url = 'http://localhost:3000/tasks?user_id=1';
// fetch可以直接使用,不用下载任何第三方库
fetch(url)
.then(res=>res.json())
.then(res=>{
console.log(res);
})
在浏览器中打开:
啊哦,报错了。has been blocked by CORS policy是典型的跨域报错
跨域
上面是一个跨域请求。因为当前 html 的页面路径是:5000,请求的的接口域名和端口号是:3000。端口号不一样,被浏览器的跨域协议拦截了
跨域(Cross-Origin Resource Sharing, CORS)是指浏览器的同源策略(Same-Origin Policy)限制,当前网页的源(origin)与要请求的资源的源不同时就会发生跨域。
源(origin)由三部分组成:
一旦发生跨域, 浏览器就阻止我们和服务器正常通信
但是不慌,还是有解决办法的。
将页面放在和接口相同的源中。相同的源,自然就没有跨域的问题了服务器的响应头中添加Access-Control-Allow-Origin等一系列允许跨域的设置。这些设置就是告诉浏览器:我允许某某浏览器和我通信设置中间代理
看完上面三种方法,是不是还有点懵,没关系,我刚开始学习也有点懵。要理解上面的三种方法,可以回头看看上面报错信息。
翻译一下:
CORS 策略已阻止从源“:55001”获取“:3000/tasks?user_id=1”的访问:请求的资源上不存在“Access-Control-Allow-Origin”标头。如果不透明的响应满足您的需求,请将请求的模式设置为 'no-cors' 以在禁用 CORS 的情况下获取资源。
这里有一个关键信息:请求的资源上不存在“Access-Control-Allow-Origin”标头。它的意思是接口返回的响应头中没有Access-Control-Allow-Origin信息,所以浏览器要阻止我们的正常通信。也就是说服务器加上这个Access-Control-Allow-Origin就不会有跨域问题了。
可以这么说,请求跨域了,浏览器报不报错,是服务器说了算!浏览器只是一个中介!
跨域请求的流程是这样的:
这里面隐含了一个关键信息,就算请求跨域了,服务器还是能收到请求的,并且一般情况下是正常返回数据的。但是浏览器作为中介会对跨域的请求做检查。
解决跨域
好了,理解完跨域的本质后,再回过头看看上面三种方法,是不是更清楚些呢?
第一种同源办法,肯定能解决,页面和接口同源了,自然就没有跨域的请求了。第二种方法,是给服务器的响应头设置Access-Control-Allow-Origin,这也好理解,浏览器在检查的时候,就是看这个东西。
但是有个问题前两种办法都是要动服务器的,很多时候服务器肯定不是前端想改就能改的。所以就只有第三种办法了。
第三种办法是设置中间代理。中间代理听起来高大上,其实就是一个服务器,用来转发跨域请求的。有了中间代理后,跨域请求就变成了下面这样:
看完上面的图后,是不是对中间代理这个解决办法醍醐灌顶了?
原来中间代理的作用是给实际服务器返回的响应头加上Access-Control-Allow-Origin等等信息的!
好,说干就干。
中间服务器
回顾上面的 fetch代码:
const url = 'http://localhost:3000/tasks?user_id=1';
fetch(url)
.then((res) => res.json())
.then((res) => {
console.log(res);
});
目的服务器是:3000
中间服务器要做的是收到的所有请求,都转发给:3000
中间服务器代码(不用看懂,可以跳过代码部分):
const http = require('http');
const url = require('url');
const PORT = 6600; // 代理服务器端口
const proxy = (req, res) => {
// 解析请求的 URL
const parsedUrl = url.parse(req.url);
// 目标服务器: http://localhost:3000
// 创建目标请求的选项
const options = {
hostname: 'locahost',
port: '3000',
path: parsedUrl.path,
method: req.method,
headers: req.headers,
};
// 发起请求到目标服务器
const proxy = http.request(options, (targetRes) => {
// 设置响应头
res.writeHead(targetRes.statusCode, targetRes.headers);
// 将目标服务器的响应数据传递给客户端
targetRes.pipe(res, {
end: true,
});
});
// 将客户端请求体的数据传递给目标服务器
req.pipe(proxy, {
end: true,
});
};
// 创建服务器
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', '*');
res.setHeader('Access-Control-Allow-Headers', '*');
if (req.method === 'OPTIONS') {
res.end();
} else {
proxy(req, res);
}
});
// 启动代理服务器
server.listen(PORT, () => {
console.log(`反向代理服务器正在运行,访问 http://localhost:${PORT}`);
});
上面用 nodejs 写了一个中间服务器,将收到的所有的请求都转发给localhost:3000,并且将返回给浏览器的响应头加上了Access-Control-Allow-Origin等信息:
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', '*');
res.setHeader('Access-Control-Allow-Headers', '*');
上面的代码看不懂没关系,也没想让你懂,就是想给你一个感性的认识:服务器不是一个神秘的高大上东西
启动服务器:
中间服务器的端口是6600,所以我们要修改 fetch 代码,将请求发到localhost:6600:
const url = 'http://localhost:6600/tasks?user_id=1';
fetch(url)
.then((res) => res.json())
.then((res) => {
console.log(res);
});
刷新浏览器,看看效果:
很好,报错消失了,成功看到了接口返回的数据
小结
上面演示了用 fetch 发起一个简单的 GET 请求,虽然代码很简单,但是其中碰到的跨域问题,却不简单,专门写了一个中间代理来解决这个问题。
那以后我们本地开发都要先写一个这样的中间代理服务器吗?当然不是,现代前端开发已经很成熟了,这些都有现成的工具,拿来直接用就好。后面会讲到这部分的内容,这里先跳过。
fetch 发起 GET 请求
下面回到正题。我们这篇文章讲的是通过看 API 文档,来写对应 JS 代码的。
有这样一个接口:
这个接口的请求方式是 GET,路径是/tasks,请求参数类型是 Query,上篇文章说过,这种类型的参数是以键值对的方式拼接在 url 后面发送给后端的。拼接方式是?key1=value1&key2=value2:
// 请求到中间服务器,中间服务器会讲请求转发指实际服务器
const url = 'http://localhost:6600/tasks?user_id=2&isCompleted=true';
fetch(url)
.then((res) => res.json())
.then((res) => {
console.log(res);
});
执行代码,查看控制台:
成功!
fetch 发起 POST 请求
fetch 发起 get 请求的代码很简单,fetch 发起 post 请求怎么做呢?
有这样一个接口:
这个接口的请求方式是 POST,路径是/tasks,请求参数是 body 传输,数据类型是 json,也可以说是一个对象。
// 请求到中间服务器,中间服务器会讲请求转发指实际服务器
const url = 'http://localhost:6600/tasks';
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json', //设置请求体的类型为json
},
// 传输请求体
body: JSON.stringify({
user_id: 2,
title: '测试标题',
}),
})
.then((res) => res.json())
.then((res) => {
console.log(res);
});
执行上面的代码,看看控制台:
请求成功,控制台顺利打印出服务器返回的数据
对于其他类型的请求,PUT,DELETE等等,和 POST 写法一样,没有什么区别
fetch(url, {method: 'PUT'}); //发送PUT请求
fetch(url, {method: 'DELETE'}); // 发送DELETE请求
我们再看一个接口:
这个接口的请求方式是 DELETE,路径是/tasks/{id},请求参数有两种,一个 path,也是直接拼在路径后面。如果 path 为 11,那拼接在路径后面就是tasks/11
path 传参的方式是很简洁,也很常用的的传参方式
还有一个请求参数是放在 body 里面的,也是以 json 数据类型传输。
下面看代码:
const url = 'http://localhost:6600/tasks/11';
fetch(url, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_id: 2,
}),
})
.then((res) => res.json())
.then((res) => {
console.log(res);
});
是不是很简单?
JSON 和 JS 对象的区别
在 JS 中,对象是键值对的集合,而 json 也是键值对的集合,它们之间有什么区别呢?
它们不是同一个东西。对象是 JS 中的一种数据类型,而 json 是指网络传输中的一种数据格式(数据格式还有很多图片啊,html 啊,音频啊等等)
因为它们很像,都是键值对的集合,所以很容易搞混。
json 就是一个静态文本,一个特殊格式的文本。
如果我们想要读取 json 里面的数据,需要将 json 转成对象。
const jsonData = '{ "name": "zenos" }';
const objData = JSON.parse(jsonData);
console.log(objData.name); // "zenos"
console.log(typeof objData.name); // "string"
对象也可以转成 JSON 字符串
objData.name = 'blue';
const jsonData2 = JSON.stringfy(objData);
console.log(jsonData2); // '{ "name": "blue" }'
文本和字符串是一个东西,只是从不同的角度来看。从数据传输的格式来看,json 就是一个文本。从编程的数据类型来看,json 就是一个字符串
总结
这篇文章讲了根据 API 文档,使用 fetch 发送 GET 请求,以及POST,DELETE请求,并且都成功地将服务器的返回值打印了出来。还讲了遇到跨域问题,前端自己应该怎么处理,用的是中间服务器的方式来做的。