什么是数据库?//只要一个东西可以永久存放数据就是数据库,不管是硬盘啊,光盘啊~~~
MYSQL 即是软件,也是一种数据库,这个软件的功能,就是数据库.MYSQL,是最流行的数据库,my是作者女儿的名字缩写,SQL是一种结构化查询语言~
- 文件系统就是一种数据库,文件可以增删改查
- 数据库,能长久存储数据的地方就是数据库,不管是光盘,硬盘~都是
- 提到了之前的http服务器知识,其中提到了请求路径和文件名只是恰巧一样而已,两者并没有关联关系
- 在服务器上做一个简单的加法运算
button.addEventListener('click',(e)=>{
let n = amount.innerText
let number = parseInt(n,10) // n-0也行,因为JavaScript的运算符的转换机制
let newNumber = number - 1
amount.innerText = newNumber
//这是页面按钮,被点击,100余额就被减少,可是这只是页面上的操作,当页面刷新,数字还是变回100,那么这些代码就失去意义了~/所以需要数据库的存在,把数据存在数据库里面,变化能够记住~
})
给页面上的余额一个占位符,因为有很多个用户,不可能每个用户都只有100余额吧
前端后端代码有关联但不是一起的,所以前端后端出现同名变量很正常,后台代码
逻辑: JavaScript页面代码只是操作页面的动作,后台没有数据记忆,所以需要用能发post请求的标签(用到标签当然是html的范畴了)去更改后台数据库的数据,/为什么是post? 因为是修改东西,并不是请求东西,也就是说,当页面付款按钮被点击,后台数据库里面的余额要知道扣多少钱,也就是说修改后台数据库里的数据所以是post请求
if(path === '/pay' && method.toUpperCase()=== 'POST'){
var amount = fs.readFlieSync
var newAmount = amount - 1
fs.writeFileSync('./db',newAmount)
response.write('success')
response.end()
}else{....
也就是说:浏览器向服务器请求网页文件,服务器响应,给浏览器对应文件,浏览器渲染整个页面,当用户点击页面上被form标签包裹的付款按钮,浏览器就发送post请求告诉服务器,数字更改了;服务器获取到这个信息,然后去数据库修改数据并且保存,又响应浏览器,实现前端后端数据一致
//老师演示的代码,后端是用了代码自动减一来实现,实际上并没有监听到余额
- 2005年之前都是这样付款的,付款之后都要刷新一下当前页面,才知道付款是否成功,体验是比较差的~
- 于是程序员们,想尽办法提升用户体验,首先想到的是用iframe+form表单标签,因为form标签会刷新当前页面,不管成功失败
- 第二种办法,前端人员发现,用JavaScript代码,新建一个img标签,就会自动发送一个get请求,JavaScript里面的image.onload方法可以检测到浏览器图片下载成功,image.onerror方法可以知道浏览器图片下载失败,利用这个特性,实现页面自动刷新,不用让用户自己动手,提升体验//这个方法缺陷是,只有get没有post//
let image = document.createElement('img')
image.src = '/pay'
iamge.onload = function(){alert'打钱成功' amount.innerText -1 }
image.onerror = function (){
alert('打钱失败')}
- 所以第三种办法想出来了,用script标签,不过这个script标签必须要放在body里面才会自动发送请求这个思路是后台直接修改数据'值'(也就是后台帮页面修改数据值),不用浏览器刷新了,彻底提高体验效果
- 说白了,就是让服务器返回一个 'conten-type'为JavaScript的字符串,让浏览器执行这些字串,效果一样,就不用像以前那样刷新页面了~完美
///这是前端的
button.addElementListener('click',(e)=>{
let script = document.createElement('script')
script.src ='/pay'
document.body.appendChild(script)//如果不包裹在body里面这个生成的script是没有自动发送的效果的
script.onload = function(e){
e.currentTarget.remove//这只是移除这个script标签,代码变量都在内存里面,没有删除,所以效果出来了,标签也删除了,完美
}
})
script.onerror = function(xxx){
alert('fail')
e.currentTarget.remove() //因为服务器返回的是可执行的JavaScript代码字符串,所以script会执行,在network下面会多出多个无用字符,这是为了清除这些无用字符的,为了美观
}
///为什么这些字串页面会执行呢?满足了2个条件,首先我们用的是script.src发送的请求,第二个服务器返回的content-type写的是JavaScript类型,这代码自然会执行
///这是后端的
if (path === '/pay'){
var amount = fs.readFlieSync('./db','utf-8')
var newAmount = amount - 1
fs.writeFlieSync('./db',newAmount)
response.setHeader('Conten-Type','application/JavaScript')
response.statusCode = 200
response.write('amount.innerText = amount.innerText - 1')
response.end()
}
//这种技术叫SRJ 服务器-S/返回的-R/JavaScript-J/就是这个意思
//由于script标签是可以跨域的,因此通过SRJ技术就可以实现两个不同域的前端和服务器之间的交流,这区别于以前的同域前端后端交互
现在版本,就是上面的改良版,升级版//利用script标签.src可以访问别的网站这个特性,除非他防盗链
- 先有jsonp然后才有的ajax
- 上一个版本的SRJ存在一个代码耦合问题,后端代码控制前端代码,或者说耦合性太强,会导致一个问题, 就是后端必须非常了解前端,甚至于要了解到页面上的细节,就如展示的上个版本SRJ代码,就存在这个问题,如果是简单的几行代码没什么关系,可是真正的工作中,面临的是庞大的代码量,而且SRJ升级版本是要跨域名请求的,比如一个百度后台程序员,哪里知道腾讯官网前端代码的细节啊~这就存在一个很严重的耦合问题
//如何解决?//解耦啊后端直接调用函数,让前端封装这个函数,并且在发送script请求的时候把这个函数名发送给后端,让服务器知道,这段话才是本节课的重中之重!!!!!!!!!!!!!
//这就意味着,前后端耦合,这就意味着后端必须对前端页面的细节很了解才能写出很好的响应,这不好!就像一个百度前端访问腾讯的后端,细节不了解就意味着难以解决两个网站之间的交流问题,因为耦合,必须腾讯后端很了解百度前端代码,这是不靠谱的
//这段话什么意思?
- 由于前面的打好了基础:script可以跨域请求,后端返回字串,因为返回的是script字串,所以前端会执行这些script字串
- 为了前后端解耦,使得两个网站更好交流,就让前端封装好一个函数,并且告诉后端这个函数名,后端返回的字串就是执行这个函数的script字串,这样做的好处就是解耦,后端不用了解前端任何细节,返回一个执行的函数就ok了
- 前端如何告诉后端这个callback函数的呢?
//传参啊 src="http//www.baidu.com/pay?callbackName=xxx" - 后端怎么获取这个callback函数的呢?
// ${query callback}.call(undefined,'成功或者失败') - 这个callbackName就是程序员之间的约定俗成
//补充一点,浏览器提供了onloading和result 这些接受结果的api - 终于知道什么是jsonp了,jsonp其实就是两个不同域之间的网站交流,服务器返回的数据用json语法写,所以叫做jsonp,服务器返回的是符合JSON语法的一串字符串,这才是本质
Jsonp就是解决两个网站之间,的交流问题~老方把这技术叫:动态标签跨域请求
总结,JSONP是怎样的一种技术:
请求方:frank.com 的前端程序员(浏览器)
响应方:jack.com 的后端程序员(服务器)
请求方创建 script,src 指向响应方,同时传一个查询参数 ?callbackName=yyy
响应方根据查询参数callbackName,构造形如
yyy.call(undefined, '你要的数据')
yyy('你要的数据')
这样的响应
浏览器接收到响应,就会执行 yyy.call(undefined, '你要的数据')
那么请求方就知道了他要的数据
这就是 JSONP
callbackName这个名字,是行业约定俗成的
yyy这个函数名是随意起的,因为可能请求多个网站啊,为了不重复就用了一个随机数,来做函数名
完整实现一次JSONP的代码,以便温习
button.addEventListener('click', (e)=>{
let script = document.createElement('script')
let functionName = 'frank'+ parseInt(Math.random()*10000000 ,10)
window[functionName] = function(){ // 每次请求之前搞出一个随机的函数
amount.innerText = amount.innerText - 0 - 1
}
script.src = '/pay?callback=' + functionName
document.body.appendChild(script)
script.onload = function(e){ // 状态码是 200~299 则表示成功
e.currentTarget.remove()
delete window[functionName] // 请求完了就干掉这个随机函数
}
script.onload = function(e){ // 状态码大于等于 400 则表示失败
e.currentTarget.remove()
delete window[functionName] // 请求完了就干掉这个随机函数
}
})
//后端代码
...
if (path === '/pay'){
let amount = fs.readFileSync('./db', 'utf8')
amount -= 1
fs.writeFileSync('./db', amount)
let callbackName = query.callback
response.setHeader('Content-Type', 'application/javascript')
response.write(`
${callbackName}.call(undefined, 'success')
`)
response.end()
}
...
课后思考:
- 除了课堂展示几个标签,还有哪些标签是可以发送请求?
- 什么是同源策略?
- 为什么标签只能发送get请求?
- JSONP技术意义何在?
- AJAX JSONP具体使用?