花了一天的时间学习JSONP,总结一下以后方便回顾。在了解什么是JSONP前,需要先了解什么是数据库,如何向服务器进行请求得到响应,可以用那些方式发送请求?如何向不同的服务器发送请求并获得响应?然后推出啥是JSOPN?内容有些长~~

一、数据库是什么?

  • 文件系统就是一种数据库:能长久存数据,能够对内容进行增、删、改、储存

  • MySQL是一种数据库

二、向数据库做加法

要做的流程如下: 点击“提交1元钱”发送请求给服务器,服务器修改数据库内容,响应返回所需数据。 用两种方式来做:图片请求;script请求;

方案一:用图片的src向服务器发送get请求

html代码如下:

<body>
    <p>账户金额:<span id="amount">!!!amount!!!</span></p>
    <button id="button">付款1元钱</button>
    <script>
        button.addEventListener('click', (e)=>{
            let image = document.createElement('img')
            image.src = '/pay'
            image.onload = function(){ // 状态码是 200~299 则表示图片请求成功
                alert('成功')
            }
            amount.innerText = amount.innerText -1
            image.onerror = function(){ // 状态码大于等于 400 则表示图片请求失败
                alert('失败')
            }
        })
    </script>
</body>

其中!!!amount!!!表示一个占位符,后端通过获取这个占位符把数据库里的内容赋值给它。

解释:当用户点击button按钮的时候,用图片发送了路径为/pay的GET请求给服务器。服务器收到后执行下面的代码,依次是: 1、判断路径 2、读取数据库的内容,假如是9966。原始数据设置的是10000 3、在最新的内容减1,并保存给变量newAmount 4、把newAmount保存到数据库,那么这个时候的值应该为9965 5、确定返回给浏览器的内容类型为 image/jpg 6、返回一张图片 7、结束

服务器代码如下:

if(path === '/'){
    let string = fs.readFileSync('./index.html','utf8')
    let amount = fs.readFileSync('./db.xxx','utf8') //db.xxx文件储存字符串10000
    string = string.replace('!!!amount!!!',amount)
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(string)
    response.end()
  }else if(path === '/style.css'){
    let string = fs.readFileSync('./style.css','utf8')    
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/css;charset=utf-8')
    response.write(string)
    response.end()
  }else if(path ==='/pay'){
    let amount = fs.readFileSync('./db.xxx','utf8')
    var newAmount = amount -1
    fs.writeFileSync('./db.xxx',newAmount)    
    response.setHeader('Content-Type', 'image/jpg')    
    response.write(fs.readFileSync('./1.jpg'))
    response.end()
  }else{
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write('呜呜呜')
    response.end()
  }

image发送get请求的缺点:得返回一张图片,同时无法获取其他的数据内容。

方案二:用script的src向服务器发送get请求

html代码如下:

<body>
    <p>账户金额:<span id="amount">!!!amount!!!</span></p>
    <button id="button">付款1元钱</button>
    <script>      
    button.addEventListener('click', (e)=>{
        let script = document.createElement('script')
        script.src = '/pay'
        document.body.appendChild(script)  //image是不需要插入,但script要插入,记住
        script.onload = function(e){   // 状态码是 200~299 则表示图片请求成功
            e.currentTarget.remove()   //删除script标签 
            alert('成功')
        }
        script.onerror = function(){ // 状态码大于等于 400 则表示图片请求失败
            e.currentTarget.remove()   //删除script标签 
            alert('失败')
    }
        })
    </script>
</body>

解释:当用户点击button按钮的时候,用scrip发送了路径为/pay的GET请求给服务器。服务器收到后执行下面的代码,依次是: 1、判断路径 2、读取数据库的内容,假如是9966。原始数据设置的是10000 3、在最新的内容减1,并保存给变量newAmount 4、把newAmount保存到数据库,那么这个时候的值应该为9965 5、确定返回给浏览器的内容类型为 JavaScript 6、返回一段JS代码,用来更改浏览器用户看到的数字 7、结束

服务器代码如下(只有path ===‘/pay’变动):

else if(path ==='/pay'){
    let amount = fs.readFileSync('./db.xxx','utf8')
    var newAmount = amount -1
    fs.writeFileSync('./db.xxx',newAmount)   
    response.setHeader('Content-Type', 'application/javascript')  //返回内容类型为 js
    response.write(`
    amount.innerText=amount.innerText-1      
    `)   //返回JS代码执行,账户余额减1
    response.end()
}

script请求与image请求相比优劣:不用返回一个图片,速度回更快一些,同时可以返回其他的内容。但动态创建的script会被执行,响应结束立刻删除e.currentTarget.remove()

这种技术就叫做 SRJ - Server Rendered JavaScript 这种技术就叫做 SRJ - Server Rendered JavaScript 这种技术就叫做 SRJ - Server Rendered JavaScript

三、跨域SRJ - JSONP

1、什么是JSONP(文字解释)

2、代码解释

html代码如下:

<body>
    <p>账户金额:<span id="amount">!!!amount!!!</span></p>
    <button id="button">付款1元钱</button>
    <script>
    button.addEventListener('click', (e)=>{
        /***以下内容为服务器获取参数返回相关值并调用的函数***/
        let functionName = 'frank'+parseInt(Math.random()*10000,10)
        //frank12312423423
        window[functionName] = function(result){
        if(result === 'success'){
            amount.innerText = amount.innerText -1
        }else{
        }
    }
        /******以下内容为动态创建script发送请求,提供参数*********/
        let script = document.createElement('script')
        script.src = 'http://jack.com:8002/pay?callbackName='+functionName
        document.body.appendChild(script)  //image是不需要插入,但script要插入,记住
        script.onload = function(e){   // 状态码是 200~299 则表示图片请求成功
            e.currentTarget.remove()   //删除script标签 
            delete window[functionName]
        }
        script.onerror = function(){ // 状态码大于等于 400 则表示图片请求失败
            e.currentTarget.remove()   //删除script标签 
            delete window[functionName]
    }
        })
    </script>
</body>

解释:请求方为http://frank.com,请求http://jack.com的服务器(响应方),通过动态script标签来请求的。服务器收到请求后执行:

1、判断路径 2、读取数据库的内容,假如是9966。原始数据设置的是10000 3、在最新的内容减1,并保存给变量newAmount 4、把newAmount保存到数据库,那么这个时候的值应该为9965 5、确定返回给浏览器的内容类型为 JavaScript 6、返回内容为:用${query.callbackName}获取浏览器提供的参数yyy,返回请求方所需要的数据,可以是JSONP 7、结束

服务器代码如下:

else if(path ==='/pay'){
      let amount = fs.readFileSync('./db.xxx','utf8')//100
      var newAmount = amount -1
      fs.writeFileSync('./db.xxx',newAmount)   
      response.setHeader('Content-Type', 'application/javascript')
      response.write(`
        ${query.callbackName}.call(undefined,{
            "success":true,
            "left":${newAmount}
        `})     
      )
      response.end()
  }

约定: 1、callbackName 必须叫做 callback / jQuery callback 2、funcitonName 为 随机数 frank12312312312321325()

3、用jquery来实现JSONP,代码更加的简洁

服务器代码不变,html代码如下:

<body>
   <p>账户金额:<span id="amount">!!!amount!!!</span></p>
   <button id="button">付款1元钱</button
   <script>
   button.addEventListener('click', (e)=>{
  
      //这个方法不是ajax,只是一个动态script
       $.ajax({
           url: "http://jack.com:8002/pay",
           dataType: "jsonp",
           success: function( response ) {
               if(response === 'success'){
                    amount.innerText = amount.innerText - 1
                }
            }
         })
         $.jsonp()
     })
 </script>
     <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
</body>

解释:url写明响应方的路径;dataType写明回应的内容类型;当响应成功执行什么样的函数;其他复杂的删减内容jQuery已经做完了。注意这个方法不是ajax,只是一个动态script进行跨域请求,可以叫做JSONP。

四、两个问题

1、什么是JSONP

2、JSONP为什么不支持POST请求?

因为JSONP是通过动态创建script来实现的跨域请求的,而script只能发送GET请求。