阿美利加大统领得小感冒引发的思考: ajax+node+promise+nginx 实现一次简单的本地联调

it2024-11-25  24

阿美利加大统领得小感冒引发的思考: ajax+node+nginx 实现一次简单的本地联调

server部分nginx 反向代理html 页面部分封装ajax请求函数纯promise 实现异步读取新闻和评论async和await 实现异步读取新闻和评论

最近在练习前后端联调的时候,做了一个练习:

通过前端页面localhost:8001的ajax 向后端服务器localhost:8000发送一个路由为api/getNews的请求,服务器返回 阿美利加大统领得感冒的新闻,并在返回对象中带了一个commentsURL路由对象。前端页面解析返回的response,解析出commentURL路由,并根据这个路由拿到关于 阿美利加大统领得感冒 这个新闻的评论。为了突出联调过程本身,对服务器逻辑做了最大程度的简化。server服务器没有链接数据库,因此也不需要请求URL中包含诸如?id=123&time=124124这样的query部分,而是简单地根据路由返回的假数据。整个过程全部用原生的javascript 完成,没有用到 jQuery 和 express 这样的库。

server部分

下面是server部分的代码:

const http = require('http') const querystring = require('querystring') const PORT = 8000; const server = http.createServer((req, res) => { const method = req.method const url = req.url const path = url.split('?')[0] const host = req.headers.host const query = querystring.parse(url.split('?')[1]) res.setHeader('Content-type', 'application/json') const resData = {} console.log(resData) if (method === 'GET') { // 处理不同路由 if (path === '/api/getNews') { resData.title = "阿美利加大统领确诊新小感冒" resData.content = "blablablablablabla" resData.commentURL = `/getComments?id=${query.id}` } if (path === '/api/getComments') { resData.comments = "卧槽这老头太牛逼了!" } res.end( JSON.stringify(resData) ) } }) server.listen(PORT)

就是建立一个服务器监听8000端口,如果GET请求的路由是/api/getNews, 那么返回阿美利加大统领得感冒的新闻; 如果GET请求的路由是 /api/getComments ,那么返回“卧槽这老头太牛逼了!”的评论。

nginx 反向代理

由于我们的页面和服务器都是在localhost上,因此我们要给返回页面的http-server和返回新闻数据的server设置不同的端口以免冲突。这里给http-server设置8001端口,而返回新闻数据的server还是之前设置的8000端口。 但是由于CORS 同源策略,这样直接跨域访问Chrome是会报错的,因此我们要用到nginx反向代理,将http-server和返回新闻数据的server的请求统一到一个端口:比如说8080。 具体的逻辑是: 如果请求的路由是 localhost:8080/(由浏览器发出),那么nginx会将请求代理到 localhost:8001上,也就是http-server所在的端口,这时候8001端口会将html和依赖的img,css,js等文件返回;如果请求的路由是localhost:8080/api(由html页面的ajax请求发出),那么nginx会将请求代理到 localhost:8000上,也就是返回新闻数据的server上。

nginx的配置很简单:

worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8080; server_name localhost; location / { proxy_pass http://localhost:8001; } location /api { proxy_pass http://localhost:8000; proxy_set_header Host $host; } } }

html 页面部分

然后是前端页面,只有一个按钮就是向服务器发送请求得到新闻和评论:

整个页面只有这一个按钮。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My first html with ajax</title> <style> .btn01 { display: block; width: 160px; height: 90px; } </style> </head> <body> <button class="btn01"> click here to send ajax request </button> </body> </html>

封装ajax请求函数

然后封装了一个发送ajax请求的函数: 其中,obj2query是将query封装成字符串添加到URL里发给服务器,myAjax接受URL,queryobj(query对象),timeout(如果超过这个时间没有接收到响应则 abort 掉这个ajax请求,而success和error参数则分别是成功连接到服务器和连接失败的回调函数。

const obj2Query = (queryObj) => { //将query对象封装成字符串的函数 // 兼容IE5,6,加入时间戳使得每次query都不一样 queryObj.t = Date.now() let temp = [] for (key in queryObj) { temp.push(`${encodeURIComponent(key)}=${encodeURIComponent(queryObj[key])}`) } return temp.join('&') } const myAjax = (url, queryObj, timeout, success, error) => { //0. 解析出完整的url queryObj = queryObj || {} //防止queryObj为undefined url += '?' + obj2Query(queryObj) console.log("myAjax", url) //1. 创建一个ajax请求 let timer const xmlHttp = new XMLHttpRequest() //2. 打开请求,并设置ajax请求的格式 xmlHttp.open('GET', url, true) //3. 向服务器发送ajax请求 xmlHttp.send() //4. 监听ajax请求的状态变化 xmlHttp.onreadystatechange = () => { if (xmlHttp.readyState == 4) { //if response, stop the timeout clearTimeout(timer) if (xmlHttp.status >= 200 && xmlHttp.status <= 300 || xmlHttp.status === 304) { console.log("get server response successfully") success(JSON.parse(xmlHttp.responseText)) } else { console.log(`Didn't get the response,status code:${xmlHttp.status}`) error(xmlHttp) } } } //5. 设置超时 if (timeout) { //如果传入了指定的timeout timer = setTimeout(() => { console.log('response timeout') xmlHttp.abort() }, timeout) } }

设置一个函数,函数中创建一个promise对象,promise中调用刚刚写好的myAjax函数,然后将这个promise对象返回出去。

function getNewsAndComments(url, queryObj, timeout) { const promise = new Promise((resolve, reject) => { myAjax(url, queryObj, timeout, (res) => { resolve(res) }, (err) => { reject("暂时没有新闻内容") }) }) return promise }

纯promise 实现异步读取新闻和评论

然后相应地在前端页面部分,调用上面定义好的 getNewsAndComment 函数:

<script> window.onload = () => { let btn01 = document.querySelector('.btn01') btn01.onclick = () => { const url = "http://localhost:8080/api" let queryObj = { //由于是假数据,这个queryObj其实是非必要的 id: "42891" } //先获取新闻页面 getNewsAndComments(url+'/getNews', {}, 3000).then( (value) => { //获取新闻页面成功了之后,再封装新的URL,根据这个url去获取评论数据 const newUrl = `${url}${value.commentURL}` return getNewsAndComments(newUrl, {}, 3000) }, (reason) => { reject("获取新闻失败!") } ).then( (value) => { alert(value) } ) } } </script>

async和await 实现异步读取新闻和评论

或者可以用async和await,用上面定义好的getNewsAndComments来异步获取新闻评论

const sendXml = async ()=>{ let result = await getNewsAndComments(url+'/getNews',{},3000).catch(console.log("获取新闻失败!")) result = await getNewsAndComments(url+result.commentURL) console.log(result) } sendXml()
最新回复(0)