jsonp 解决同源限制 跨域 原理解析 函数封装

概念

jsonp(json with padding),它不属于Ajax请求,但它可以模拟Ajax请求
将json数据当做填充内容

原理

  1. 将不同源的服务端请求地址写在script标签的src属性当中
// 通过script向不同源的服务端发送请求
<script src="www.example.com"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  1. 服务端响应数据必须是一个函数的调用,真正要发送给客户的数据需要作为函数调用的参数。
const data = 'fun({name:"张三",age:"20"})'
res.send(data)
  1. 在客户端全局作用域定义函数fun 要在script之前
fun(data){}
  1. 在函数fun内部进行服务端返回的数据进行处理
fun(data){
	console.log(data)
	// 数据的处理
}

原理示例

开启2个服务器 s1 s2
s2 app.js

const express = require("express")
const path = require("path")
const app = express()

// 开启静态资源访问
app.use(express.static(path.join(__dirname,'public')))

app.get("/test",(req, res)=>{
    let obj = {
        name:"张三",
        age:18
    }
    res.send(`fun(${JSON.stringify(obj)})`)
})

app.listen(3001,()=>{
    console.log("s2 服务器启动")
})

s1 app.js

const express = require("express")
const path = require("path")
const app = express()

// 开启静态资源访问
app.use(express.static(path.join(__dirname,'public')))

app.listen(3000,()=>{
    console.log("s1 服务器启动")
})

s1 public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>s1 html</title>
</head>
<body>
    请求 http://localhost:3001/test 
    <script>
        // 定义全局函数
        function fun(data){
            // let dat = JSON.parse(data)
            console.log("dat",data)
        }
    </script>
    <!-- 将非同源服务器端的请求地址写在script标签的src -->
    <script src="http://localhost:3001/test"></script>
</body>
</html>

效果
在这里插入图片描述

优化示例

  1. 客户端要将函数名称传递到服务端
  2. 将 script 请求发送变成动态请求(动态添加script标签到页面)
  3. 封装jsonp函数

s2 app.js

const express = require("express")
const path = require("path")
const app = express()

// 开启静态资源访问
app.use(express.static(path.join(__dirname,'public')))

app.get("/test",(req, res)=>{
    let obj = {
        name:"张三",
        age:18
    }
    
    // 接收回调函数名称
    // let callback = req.query.callback
    // res.send(`${callback}(${JSON.stringify(obj)})`)

    // 使用方法等同于 上面的代码 回调函数的属性名 为 callback
    res.jsonp(obj)
})

app.listen(3001,()=>{
    console.log("s2 服务器启动")
})

s1 public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>s1 html</title>
</head>
<body>
    http://localhost:3001/test
    <button id="btn">发送请求  </button>
    <script>
        // 定义全局函数
        function fun(data){
            // let dat = JSON.parse(data)
            console.log("dat",data)
        }
        let btn = document.getElementById("btn")
        btn.onclick = function(){
            var script = document.createElement('script');
            script.src = 'http://localhost:3001/test?callback=fun'
      
            // 把srcipt添加到页面当中 就会开始请求
            document.head.appendChild(script)

            script.onload = function(){ //js加载完触发
                // 请求完成移除script标签
                script.remove()
            }
            
//			myjsonp({
//			    url:'http://localhost:3001/test',
//			    params:{
//			        id:99
//			    },
//			    success:function(res){
//			        console.log("res",res)
//			    }
//			})
        }
    </script>
</body>
</html>

封装jsonp

调用

myjsonp({
    url:'http://localhost:3001/test',
    params:{
        id:99
    },
    success:function(res){
        console.log("res",res)
    }
})

封装

/*
 * 封装jsonp
 * obj
 *    url:请求地址
 *    params 参数
 *    success 成功回调
 */
function myjsonp(obj){
    
    // 全局函数名称可随机生成
    let fName = '_myjsonp_'+Date.now()

    // 定义全局函数
    window[fName] = function (data){
        obj.success && obj.success(data)
    }
    obj.params.callback = fName
    
    // 参数处理
    let queryString = ''
    Object.keys(obj.params).forEach(key=>{
        queryString += key+"="+obj.params[key]+"&"
    })

    queryString = queryString.substring(0,queryString.length-1)
    obj.url += '?'+ queryString
    

    var script = document.createElement('script');
    script.src = obj.url

    // 添加到页面 开始请求
    document.head.appendChild(script)

    script.onload = function(){ //js加载完触发 请求完成
        // 请求完成移除script标签
        script.remove()
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值