> 技术文档 > 快速搭建服务器,fetch请求从服务器获取数据_fetch 同步请求

快速搭建服务器,fetch请求从服务器获取数据_fetch 同步请求


 1.strapi

        首先strapi是一个api管理系统,可以让我们直接用网页的形式去定义自己的api,包括设置模型和权限等功能。

        首先直接在项目目录里面安装库。npx create-strapi@latest server --quickstart这样就可以直接在项目目录创建一个连接数据库的服务器了。不用我们去书写代码,直接在网页版数据库添加表以及表中的数据就可以自动生成api让我们去访问请求了。

        

        就是这种,我们网页形式创建表,添加权限,自动生成api。这样我们就可以在前端发送请求去获取数据了。值得一提的是记得npm的版本以及node.js版本会有限制。

        可以装一个nvm管理自己开发项目用的node。

        我是mac系统所以用brew安装nvm brem install nvm,然后创建nvm工作目录 mkdir ~/.nvm

然后配置终端环境变量,nano ~/.zshrc 然后文件内容

Maestro CLIexport PATH=\"$HOME/.maestro/bin:$PATH\"OpenJDK 17export PATH=\"/opt/homebrew/opt/openjdk@17/bin:$PATH\"nvm 配置(Homebrew 路径,Apple M 芯片)export NVM_DIR=\"$HOME/.nvm\"[ -s \"/opt/homebrew/opt/nvm/nvm.sh\" ] && \\. \"/opt/homebrew/opt/nvm/nvm.sh\"[ -s \"/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm\" ] && \\. \"/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm\"

        然后control x退出 按y 再按回车保存退出成功。在执行立即生效命令 source ~/.zshrc这样nvm就配置好了。我们用nvm install 22装上 22版本的node.js然后nvm use 22就可以创建strapi项目了。

2.fetch 

         上面网页可以看到我们路由是/api/students,那么我们就可以尝试去用fetch(浏览器自带的发送请求的api,是浏览器提供的全局函数,返回的一个promise)所以可以用链式调用.then.catch因为promise有状态,请求成功自动执行.then失败会自动调用.catch而且参数就是返回的promise实例对象

import React, { useEffect } from \'react\'export default function App() { const [person, setPerson] = React.useState([]) const [show, setShow] = React.useState(false) /* 从接口http://localhost:1337/api/students中加载数据 组件一渲染就向服务器发送请求加载数据 组件初始化时候发送请求来加载数据 */ useEffect(() => { //说明数据开始加载了 setShow(true) //发送请求 //fetch()用来向服务器发送请求加载数据,Ajax的升级版 //需要两个参数 1.请求地址2.请求信息 //promise两个特点 成功和失败两个回调函数.then成功时候调用 .catch失败时调用 fetch(\'http://localhost:1337/api/students/\') .then((res) => { //response表示响应信息 // console.log(res); return res.json();//该方法可以将响应的json直接转换为js对象 }).then((data) => { console.log(data.data); // 将加载到的数据设置进state中 setPerson(data.data) setShow(false) }) .catch(() => { }) }, []) return ( 
{show ? (

正在加载中...

) : ( person.map((item) => (
{item.name} --- {item.gender} --- {item.age}
)) )}
)}

        这里我们没有写fetch发送请求的类型,所以是get。这里展示数据成功,说明访问成功之后把数据返回来了,但是第一次是json类型

        

        我们需要去转化成对象。比如这里再次使用.then是因为前面的.then把json转化为js对象。然后return返回的也是一个promise实例对象。所以可以.then,报错.catch捕捉。 

        

        这里转化的js对象有两个属性一个是data,一个是meta(不认识),但是我们展开确定我们需要的是data里面的对象 

        所以用setState去存住返回来的数据就可以去展示到页面上面了。就实现了第一次用fetch请求api响应数据展示的过程了。

        但是我们要知道还有一个.catch我们没有去写,比如我们去掉路由students中的s,

 

 

        返回404但是问题是map也就是map方法错了所以请求整个过程还是执行了?这很明显不对。但是我们看到ok变为false,那么我们就可以去截断这个请求过程。而且statusText都变了。

        

        对比我们就知道如果错了,ok和statueText会改变,那就对这些进行判断。

         

        比如这里,这样如果错误就不会再执行请求后面的代码了。因为只有成功才会返回promise实例对象,才可以调用后面的.then,而且.catch没有内容所以什么都没有。

import React, { useEffect } from \'react\'export default function App() { const [person, setPerson] = React.useState([]) const [show, setShow] = React.useState(false) const [err, setError] = React.useState(null) /* 从接口http://localhost:1337/api/students中加载数据 组件一渲染就向服务器发送请求加载数据 组件初始化时候发送请求来加载数据 */ useEffect(() => { //说明数据开始加载了 setShow(true) //发送请求 //fetch()用来向服务器发送请求加载数据,Ajax的升级版 //需要两个参数 1.请求地址2.请求信息 //promise两个特点 成功和失败两个回调函数.then成功时候调用 .satch失败时调用 fetch(\'http://localhost:1337/api/students/\') .then((res) => { //判断是否正常返回响应信息 if (res.ok) {  console.log(res);  return res.json() } //代码运行到这里 说明没有加载到数据 // setShow(false) //抛出一个错误 throw new Error(\'数据加载失败\') // response表示响应信息 // console.log(res); // return res.json();//该方法可以将响应的json直接转换为js对象 }).then((data) => { // console.log(data); // 将加载到的数据设置进state中 setPerson(data.data) setShow(false) }) .catch((e) => { //catch中的回调函数用来统一处理错误 //catch执行说明上面代码出错 setShow(false) // console.log(e); console.log(\'e\', e) setError(e) }) }, []) return ( 
{show &&

加载中

} {err &&

出错了:{err.message}

} {!show && !err && person.map((item) => (
{item.name} --- {item.gender} --- {item.age}
))}
)}

        当报错的时候用throw new Error(‘’)扔出一个err,然后.catch就可以捕捉到。这样就完成了整个请求的逻辑,首先要有一个state接收响应数据,还要有一个state去控制请求发送后如果没有即使响应展示的内容,还需要一个state去控制页面如果报错了展示错误信息,

3.async await语法糖

import React, { useEffect } from \'react\'export default function App() { const [person, setPerson] = React.useState([]) const [show, setShow] = React.useState(false) const [err, setError] = React.useState(null) useEffect(() => { const fetData = async () => { try { setShow(true) setError(null) const res = await fetch(\'http://localhost:1337/api/students\') if (res.ok) {  const data = await res.json()  setPerson(data.data) } else {  throw new Error(\'数据加载失败!\') } } catch (e) { setError(e) } finally { setShow(false) } } fetData() }, []) return ( 
{show &&

加载中

} {err &&

出错了:{err.message}

} {!show && !err && person.map((item) => (
{item.name} --- {item.gender} --- {item.age}
))}
)}

         

        最开始我们使用 fetch 是通过连续调用 .then 来一步步获取 response 和 json 数据,因为 fetch 返回的是一个 Promise 实例对象,不能直接取到里面的数据。而使用 await 关键字后,就相当于自动帮我们调用了 .then,把 Promise 解析后的数据直接赋值给变量。比如第一次用 await fetch... 获取响应对象 response,第二次再用 await response.json() 把 JSON 数据解析成 JS 对象。

        由于 await 是同步语法风格,我们就不能再用 .catch 来捕获错误,而需要使用 try catch finally 来捕获异常,比如 throw 抛出的错误才能在 catch 中处理。需要注意的是:只有在 async 声明的函数中才能使用 await。

4.删除数据

import React, { } from \'react\';import StuContext from \'./store/StuContext\';import StudentForm from \'./StudentForm\';const Student = (props) => { const Stx = React.useContext(StuContext) const [loading, setLoading] = React.useState(false) const [error, setError] = React.useState(null) const [isEdit, setIsEdit] = React.useState(null) const deleteData = React.useCallback(async () => { try { setLoading(true) setError(null) const res = await fetch(http://localhost:1337/api/students/${props.stu.documentId}, { method: \'delete\' }) if (!res.ok) { throw new Error(\'删除失败\') } //修改成功后触发列表重新刷新 Stx.fetchData() // const data = await res.json() // console.log(\'data\', data) // 被删除的学生 } catch (e) { console.log(e); setError(e) } finally { setLoading(false) } }, []) const Delete = () => { //删除学生 deleteData() } const cancel = () => { setIsEdit(false) } return (  {!isEdit &&   {props.stu.name}  {props.stu.gender}  {props.stu.age}  {props.stu.address}            } { isEdit &&  } { loading && 正在删除数据 } { error && 删除失败 }  );};export default Student;

        这是我们的删除请求,我们只需要在后面的对象中指名请求头为delete就可以去删除了。当然需要一个参数documentId去指名删除的哪一个。id不行在说一边我用的strapi不支持id去指定删除或者更新的表中的列。卡了一天了.............只不过一个点是Context我们用到了,因为我们

         

 

        每次在删除之后需要重新加载一遍数据,保证最新的数据在 页面上。

 <StuContext.Provider value={{ fetchData }}> 
{(!loading && !error) && } {loading &&

数据正在加载中...

} {error &&

数据加载异常!

}

        就是这样然后我们在删除请求成功之后,执行一下重新加载的方法就好了。

5.创建以及更新请求

import React from \'react\'import \'./StudentForm.css\'import StuContext from \'./store/StuContext\'export default function StudentForm(props) { const Stx = React.useContext(StuContext) const [input, setInput] = React.useState({ name: props.stu ? props.stu.name : \'\', age: props.stu ? props.stu.age : \'\', address: props.stu ? props.stu.address : \'\', gender: props.stu ? props.stu.gender : \'男\' }) const [loading, setLoading] = React.useState(false) const [err, setErr] = React.useState(null) const addData = (async (input) => { try { setLoading(true) setErr(null) const res = await fetch(\'http://localhost:1337/api/students\', { method: \'post\', body: JSON.stringify({  data: input }), headers: {  \'Content-Type\': \'application/json\' } }) console.log(\'res.ok\', res.ok) if (!res.ok) { throw new Error(\'添加失败\') } //添加成功刷新列表 Stx.fetchData() } catch (e) { console.log(e); setErr(e) } finally { setLoading(false) } }) const updataData = (async (newStu, id) => { try { setErr(null) setLoading(true) const res = await fetch(http://localhost:1337/api/students/${id}, { method: \'PUT\', body: JSON.stringify({ data: newStu }), headers: {  \'Content-Type\': \'application/json\' } }) if (!res.ok) { throw new Error(\'修改出错\') } Stx.fetchData() } catch (e) { setErr(e) } finally { setLoading(false) } }) const nameChange = (e) => { setInput((preState) => ({ ...preState, name: e.target.value })) } const ageChange = (e) => { setInput((preState) => ({ ...preState, age: +e.target.value })) } const genderChange = (e) => { setInput((preState) => ({ ...preState, gender: e.target.value })) } const addressChange = (e) => { setInput((preState) => ({ ...preState, address: e.target.value })) } const handle = () => { addData(input) } const updataHandle = () => { updataData(input, props.stu.documentId) } return (      男  女      {props.stu && }  {!props.stu && }   {loading && 添加中} {err && 添加失败}  )}

        唯一不同的是我们在执行创建或者更新请求除了请求头不同以外,创建也就是添加新表元素需要传一个json格式的文本内容,也就是我们需要把js对象转化成json格式。正好对应我们响应体json格式需要转化成js对象我们用。以及指明请求体的格式,headers:{“Content-Type:\'application/json\'”}说明我们传过去的是json格式。包括更新,毕竟我们是传过去数据而不是get获取数据。这一点要注意。好了现在我们用fetch实现了post 增 delete删 put 改 get查了。虽然不熟练但至少有个思路怎么去数据库拿东西了。至于优化还是慢慢来吧。