JSONP
数据库
有时候,我们需要长久的存储数据,不随着外界因素的改变而改变,这样的数据栖息地可以称之为数据库。
version1.0-表面工作
建立一个扣款功能做例子
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>pay</title> </head> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script> <body> <p>您的账户余额: <span id="amount">100</span></p> <button id='button'>付款1块</button> </body> <script> $('#button').on('click',() => { let n=document.getElementById('amount').innerText; n -= 1; document.getElementById('amount').innerText = n; }) </script> </html>
存在的问题
之所以称之为表面,是因为,所有的操作都是表面现象,当页面刷新时,一切都会回到初始状态。而且,别人很容易就能够获取你的信息。最好是,我们去调取数据库里你的信息,然后显示在页面上。
version2.0-将操作在后端进行
以往,我们是在前端的代码中去改用户的余额。现在,不,我们去后端直接改数据库里的余额,然后,把后端数据库的金额显示在前端页面上。而前端用来向后端发起一个请求,请求更改数据库里的余额。
<button>
显然不能发起一个请求,所以使用<form>
,表单是可以发起一个请求的,而且可以指定请求的方式:get
/post
。
前端代码:
- 使用
<form>
发起一个请求 - 请求路径
action='/pay'
- 请求方法
method='post'
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>pay</title> </head> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script> <body> <p>您的账户余额: <span id="amount">$$amount$$</span></p> <form id='button' action='/pay' method='post'> <input type='submit' value='付款1块钱'> </form> </body> </html>
使用Javascript写的后端代码:
- 修改数据库金额,返回成功提示
response.write('success');
- 读取数据库金额
- 显示数据库金额在页面上
//读取数据库金额,并显示在页面上 if(path === './'){ var index_string = fs.readFileSync('./index.html','utf8'); var amount = fs.readFileSync('./db','utf8'); index_string.replace('$$amount$$',amount); response.setHeader('Content-type','text/html;charset=utf-8'); response.write(string); response.end(); //修改数据库中金额,并返回success }else if(path === '/pay' && method === 'post'){ var amount = fs.readFileSync('./db','utf8'); var newAmount = amount - 1; fs.writeFileSync('./db',newAmount); response.write('success'); response.end(); }
效果
点击按钮:
点击付款1块钱,发送如下请求,并且页面中显示success。说明请求成功,数据库中金额修改成功!
返回页面:
查看数据库:
存在问题
有没有发现,我们每一次付款,都需要返回、刷新页面才能看到自己正确的余额。用户体验极差!
并且,<form>
表单自带特性:每一次提交,都会刷新页面。
最好是,付款之后,页面只有数字那部分局部刷新。
version3.1-iframe
<iframe>
的功能就是在页面中单开一个空间作为新的页面,我们可以将<form>
关联到这个<iframe>
上,每次提交都只刷新<iframe>
即可。
<body> <p>您的账户余额: <span id="amount">$$amount$$</span></p> <form id='button' action='/pay' method='post' target='result'> <input type='submit' value='付款1块钱'> </form> <iframe name='result' src='about:blank' frameborder='0' height=200></iframe> </body>
存在的问题
过时。虽然不需要再按返回了,但是还是需要刷新页面才能看到真正的余额。
version3.2-<img>发送请求
既然,我们不希望页面刷新,那我们就得换一个方式发送请求。铛铛铛铛!这就是<img>
!不过<img>
只能发送get
请求,不过,方法先进,用户体验良好,get
也可以接受。
前端代码:
- 注意!功能是在js里实现的
- 当点击
<button>
,创建一个<img>
,路径指向后台文件/pay
- 如果图片加载成功
image.onload=function(){}
,提示成功,并将金额amount.innerText -= 1
- 如果图片加载失败
image.onerror=function(){}
,提示失败
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>pay</title> </head> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script> <body> <p>您的账户余额: <span id="amount">$$amount$$</span></p> <button id='button'>付款1块钱</button>> </body> <script> $('#button').on('click',function(){ var amount=document.getElementById('amount'); var image=document.createElement('img'); image.src='./pay'; image.onload=function(){ alert('success'); amount.innerText -= 1; } image.onerror=function(){ alert('fail'); } }) </script>
使用Javascript写的后端代码:
- 与之前区别在于,这次不需要要用到刷新页面,当然刷新页面功能也没问题
- 与之前区别在于,这次返回的是一张图片
response.write(fs.readFileSync(你的图片路径));
//和之前一样,读取数据库中金额,并显示在页面上,但这里并不一定会用到这些代码,因为我们不需要刷新页面了 if(path === './'){ var index_string = fs.readFileSync('./index.html','utf8'); var amount = fs.readFileSync('./db','utf8'); index_string.replace('$$amount$$',amount); response.setHeader('Content-type','text/html;charset=utf-8'); response.write(string); response.end(); } //修改数据库中金额,成功后返回一张图片 else if(path === '/pay'){ var amount = fs.readFileSync('./db','utf8'); var newAmount = amount - 1; fs.writeFileSync('./db',newAmount); response.setHeader('Content-type','image/jpg'); response.write(fs.readFileSync(你的图片路径)); response.end(); }
优点
- 不用像`<iframe>一样新开辟一块地盘
- 之前的思路:修改后端数据库 → 获取数据库金额显示在页面上(需要刷新页面获得显示)
现在的思路:修改后端数据库 → 修改成功后,直接修改页面显示(不刷新);获得数据库金额(刷新) - 成功、失败的提示依赖
alert()
,不像之前需要新的页面 - 机智的地方在:虽然建立了
<img>
标签,也成功获取了一张图片,但是图片并没有显示出来,因为,我们只是在js里创建了<img>
标签,并没有把它加到页面里,没有append()
到哪里去。所以,我们利用了<img>
能够发送请求的特点,而没有真正的显示出图片。
问题
哇!这样已经很好了,可以返回一个大小很小的图片呀,或者什么乱起八糟的图片。但是,图片毕竟是图片,返回一张图片会影响响应速度。
version3.3-<script>发送请求
我们发现,<script>
居然也能发送请求,那更好了,<script>
请求返回的是空字符串,那可比图片小多了。
前端代码:
- js创建
<script>
,指定<script>
路径为./pay
- 与
<img>
发送请求不一样在于:<script>
需要加载到<body>
才能生效 <script>
加载成功:script.onload=function(){}
<script>
加载失败:script.onerror=function(){}
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>pay</title> </head> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script> <body> <p>您的账户余额: <span id="amount">$$amount$$</span></p> <button id='button'>付款1块钱</button>> </body> <script> $('#button').on('click',function(){ var amount=document.getElementById('amount'); var image=document.createElement('script'); script.src='./pay'; document.body.appendChild(script); script.onload=function(){ alert('success'); } script.onerror=function(){ alert('fail'); } }) </script>
使用Javascript写的后端代码:
- 与之前区别在于,这次不需要要用到刷新页面,当然刷新页面功能也没问题
- 与之前区别在于,这次返回的是空字符串
response.write('');
//和<img>发送请求时的没有区别 if(path === './'){ var index_string = fs.readFileSync('./index.html','utf8'); var amount = fs.readFileSync('./db','utf8'); index_string.replace('$$amount$$',amount); response.setHeader('Content-type','text/html;charset=utf-8'); response.write(string); response.end(); //修改数据库中金额,成功后返回空字符串 }else if(path === '/pay'){ var amount = fs.readFileSync('./db','utf8'); var newAmount = amount - 1; fs.writeFileSync('./db',newAmount); response.setHeader('Content-type','application/javascript'); response.write(''); response.end(); }
优化-1
在使用<script>
发送请求的本例中,我们没有在前端代码中加入,当script.onload=function(){}
时,页面中数字减一amount.innerText -= 1;
。这是因为,经过测试,
在前端代码中加入:
script.onload=function(){ //之前的代码 console.log('我是前端'); }
在后端代码中加入:
else if(path === '/pay'){ //之前的代码 response.write('console.log("我是后端")'); //之后的代码 }
结果发现,首先出现后端的console.log("我是后端")
,再出现前端的console.log('我是前端')
。
之前,我们将amount.innerText -= 1;
放在前端代码里是因为,之前使用<img>
,返回只能是一张图片;现在我们使用<script>
,返回值会被当做Javascript执行。
所以,我们直接在后端代码输入我们想要执行的前端代码就行啦