JSONP技术栈_jsonp的使用

更新日期: 2018-05-28阅读: 2.6k标签: 跨域

前面学习了这么多,都是在和页面打交道,不管是htmlcss、JavaScript,dom,都没有跑出浏览器,那今天来学习下和后台交互。


简单的前后端交互

写一个简单的node.js脚本,让我们的页面能够正常运行

  1. 创建一个文件夹里面创建两个文件
  2. 新建一个脚本文件
  3. 新建一个index.html文件
  4. 打开服务器,就可以看到自己的页面了


脚本文件

var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var path = request.url 
  var query = ''
  if(path.indexOf('?') >= 0){ query = path.substring(path.indexOf('?')) }
  var pathNoQuery = parsedUrl.pathname
  var queryObject = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  if(path === '/'){
    var string = fs.readFileSync('./index.html','utf8')
    response.setHeader('Content-Type','text/html;charset=utf-8')
    response.write(string)
    response.end()
  }else if(path === '/style.css'){
    var string = fs.readFileSync('./style.css','utf8')
    response.setHeader('Content-Type','text/css')
    response.write(string)
    response.end()
  }else if(path === '/main.js'){
    var string = fs.readFileSync('./main.js','utf8')
    response.setHeader('Content-Type','text/javascript')
    response.write(string)
    response.end()
  }else{
    response.statusCode = 404
    response.setHeader('Content-Type','text/html;charset=utf-8')
    response.end('找不到对应的路径,你需要自行修改 index.js')
  }
  
  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)

index.html文件

<!DOCTYPE html>
<html>
<head>
    <title>首页</title>
</head>
<body>
    <h5>你的余额是<span id="amount">100</span></h5>
    <button id="button">付款</button>
    <script>
        button.addEventListener('click',function(e){
            let n = amount.innerText;    //类型是String
            let number = +n;
            let newNumber = number - 1;
            amount.innerText =  newNumber;
        })
    </script>
</body>
</html>

当我们点付款的时候,100会往下减小,但是当我们刷新页面的时候,又变成了100,这里的问题是我们的数据没有长久的存储在数据库里面。

我们该怎么解决这个问题呢?

用占位符替换页面数据

我们在刚才的页面中新建一个文件,作为我们的数据库,现在我们把100元写在数据库里。

touch db
echo '100' > db

index.html中的100用一个占位符替代,这样写了好处是可以在脚本中把这个数字替换称真实的数据。

<span id="amount">&&&amount&&&</span>

在脚本中if(path === '/')里加一个替换占位符语句。

var amount = fs.readFileSync('./index','utf8')        //文件中的数据类型是String
string = string.replace('&&&amount&&&',amount)

重启服务器后,刷新页面还是问题还是没解决,怎么办呢?


form表单发请求

我点付款的时候告诉服务器,请把数据库里的100变成99,然后刷新页面;我不擅自改变了页面中的数据,那我点付款的时候,发起一个POST请求,应该怎么做呢?

<form action="pay" method="post">
    <input type="submit" value="付款">
</form>    

在服务器里面增加一个/pay请求路径。

if(path === '/pay' && method.toUpperCase() === 'POST'){
    var amount = fs.readFileSync('./db','utf8')
    var newAmount = amount - 1
    fs.writeFileSync('./db',newAmount)
    response.write('success')        //成功后给用户返回
    response.end()
}

当你点付款的时候,是不是看到success写到了页面中,点击浏览器的返回上一页,刷新下当前页面,是不是发现变成99了,前端要写的就是form表单,后端如果发现是某个路径并且是POST请求,就去操作数据库。

这是旧时代的操作,在2005年之前,都是这样操作的,form表单一旦提交了都会刷新当前页面,可以用iframe解决页面刷新的问题。

iframe解决页面刷新问题


动态创建img标签

如果不用iframe发请求,还能用什么发请求呢?有很多标签可以创建请求,比如a标签、script标签、link标签、img标签等。

那我们先来动态的创建一张图片。

button.addEventListener('click',function(e){
    let image = document.creatElevent('img')
    image.src = '/pay'
    image.onload = function(){}
    image.onerror = function(){}
})

onload和onerror是提示用户成功了还是失败,可以在成功的里面加上一个window.location.reload()成功后会自动刷新页面。

刷新页面会造成浏览器重新渲染

用这方法有两个的缺陷,那当付款成功后,页面自动减1,amount.innerText = amount.innerText - 1。

  1. 只能发起GET请求,不能发POST请求。
  2. 必须要返回真实的图片,只给一个状态码是不行的。


SRJ方案

动态创建script标签

下面再来动态创建script标签

button.addEventListener('click',function(){
    var script = document.createEvent('script')
    script.src = '/pay'
    document.body.appendChild(script)    //必须要将创建出来的Script放在页面中才可以
})

因为在页面中创建了script它是会执行的,所以这里就不需要用onload去监听了,把内容直接写在script上面,这里执行的先后顺序是先执行脚本里的script,执行完了之后才执行外面的script。

response.write(`alert("success")
amount.innerText = amount.innerText -1`)    //ES6字符串方法

用这种方法,每次都会创建一个script,显得页面很难看,还要用onload去监听。

script.onload = function(e){
    e.currentTarget.remove()
}
script.onload = function(e){
    e.currentTarget.remove()
}

当用户点击付款时,生成一个script,script的src就是你要请求的路径,然后把script放到页面里,这样浏览器就能发起这个路径的GET请求,没办法发起POST 请求,如果这个请求成功了,它首先会执行服务器返回的JavaScript 响应,操作页面局部刷新,为什么这里会执行,是因为我们上面给它设置了HTTP 协议,执行之后,onload或onerror再把它删掉,虽然删掉了但它还是在内存中。

这就是SRJ方案,全称 Server rendered javascript,在ajax出来以前,程序员想出来的,无刷新局部更新页面内容的方案。


请求另一个网站的script

在页面中引入一个script时,一定要当前域名吗?当然不是的。

那这样的话,是不是操作别人网站的/pay,所以GET请求太不安全了,太容易伪造了,所以大部分的/pay都用POST请求去做。

PORT=8002 node index.js 可以开多个端口

SRJ方案前后端耦合太紧密了,需要后端对页面了解太清楚。

其实前端提供一个xxx() api就可以了。

response.write(`
xxx.call(undefined,'success')
`)


JSONP方案

前端提供 API 的方法,其实解耦还没有解的很干净,我们在设置script的src时直接给它传参,后端插入这个参数这就可以了,看下面:

script.src = 'http://baidu.com:8002/pay?callbackName=xxx'
${query.callbackName}.call(undefined,'success')

上面就是JSONP,JSONP解决了两个网站之间的交流。

${query.callbackName}.call(undefined,{
    "success": true
    "left": ${newAmount}
})

上面call里面大括号中的内容符合 JSON 的语法,左边是left-padding,右边是right-padding,所以 JSON + padding = JSONP。


用文字叙述 JSONP

请求方:qq.com的前端程序员(浏览器)
响应方:baidu.com的后端程序员(服务器)

  1. 请求方创建script ,src 指向相应方同事传一个查询参数 ?callbackName = xxx
  2. 响应方根据查询参数callbackName,构造形如 xxx.call(undefined,'你要的数据')这样的响应
  3. 浏览器接收到响应,xxx.call(undefined,'你要的数据')
  4. 那么请求方就知道了它要的数据

这就是JSONP

约定:

  1. callbackName -> callback
  2. xxx -> 随机数

按照约定写一下

button.addEventListener('click',funcion(e){
    let script = document.creatElevent('script')
    let functionName = parseInt(Math.random()*1000000)        //这个函数名是随机数
    window[functionName] = function(result){    //result是服务器返回的结果
        if(result === 'success'){
            amount.innerText = amount.innerText - 1
        }
    }

    script.src = 'http://baidu.com:8002?callback=' + functionName    //写在参数里面
    document.body.appendChild(script)
    script.onload = function(e){
        e.currentTarget.remove()
        delete window[functionName]    //如果成功了要干掉这个函数
    }
    script.onerror = function(e){
        alert("false")
        e.currentTarget.remove()
        delete window[functionName]    //如果失败了也要干掉这个函数

    }
})


jquery实现

用jQuery就能非常方便的使用

button.addEventListener('click',function(){
    $.ajax({
        url: "http://baidu.com:8002/pay"
        dataType: "JSONP"
        success:function(response){
            console.log(response)
        }
    })
})


JSONP为什么不支持POST请求

  1. 因为JSONP是通过动态创建Script实现的
  2. 动态创建Script只有GET请求没有POST请求

原文来源:https://segmentfault.com/a/1190000015050698?utm_source=channel-hottest


链接: https://www.fly63.com/article/detial/831

web网站ajax跨域方法总结与解决方案

web前端的同学如果使用ajax,如果请求后端地址和页面访问的地址“URL的首部”不同就会出现访问被拒绝的情况,这就需要跨域来解决前后端的通讯问题,下面将列举一些在实际项目中应用也是比较多的方法。

使用CSS3特性做跨域,跨域还可以这样玩

利用js动态创建一个link插入到文档中, 请求css文件,利用 computedStyle = window.getComputedStyle 获取指定元素的 style 对象,利用 computedStyle .content 获取内容

Js通过Web代理发起跨域请求

XMLHttpRequest对象(IE中为XMLHTTP对象)是AJAX应用的核心。由于现代浏览器对跨域请求的限制,在使用时需多加注意。本教程尽量用简单易懂的话描述(跨域)问题,并提供一个方案:通过Web代理(Web Proxy)

jsonp跨域原理,jsonp和ajax的区别?

Jsonp原理是动态创建一个script标签,利用script标签src属性访问没有限制,实现跨域。Ajax是页面无刷新请求数据操作,Jsonp不是真正的ajax请求。讲解Ajax 和 jsonp的区别,在jquery中使用jsonp

CORS跨域请求

浏览器的同源策略会导致跨域,这里同源策略又分为以下两种:DOM同源策略、XmlHttpRequest同源策略。只要协议、域名、端口有任何一个不同,都被当作是不同的域,之间的请求就是跨域操作。

如何用Nginx解决前端跨域问题?

在开发静态页面时,类似Vue的应用,我们常会调用一些接口,这些接口极可能是跨域,然后浏览器就会报cross-origin问题不给调。最简单的解决方法,就是把浏览器设为忽略安全问题,设置--disable-web-security。

vue-cli3 中跨域解决方案

此方案只能用于开发环境,线上最好设置同源策略(遇到个后端,装你妈批),前后端不在同一服务器的情况下,前端要访问后端API,可通过在vue.config.js中配置代理服务器。

vue项目打包后怎样优雅的解决跨域

在使用vue.js开发前端项目时,再结合webpack搞起各种依赖、各种插件进行开发,无疑给前端开发带来了很多便捷,就在解决跨域这个问题上,相信众多用vue.js的前端同僚们同我一样尝到了甜头

nginx 反向代理处理跨域问题

正向代理是你发出请求的时候先经过代理服务器,所以实际上发出请求的是代理服务器。反向代理是“代理你的目标服务器”,请求目标服务器的代理,做一些处理后再真正请求。在这篇文章里,反向代理用于处理跨域问题。

reactjs中配置代理跨域

第一步,下载依赖 http-proxy-middleware;第二步,在src下建立setupProxy.js;第三步,在数据请求中直接请求,在真实url后添加/api即可,eg

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!