同源政策(跨域请求)

同源:如果两个页面有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。不同源的网站之间是不允许发送ajax请求的
解决方案:

1.JSONP解决同源限制问题,其整体原理如下(若想直接用可直接跳转到优化4):

假设有两个服务器,服务器 s1监听3000端口,s2监听3001端口

// s1服务器对应的前端代码
<script>
    function fn (data) {
        console.log('3000服务器的客户端被执行了')
        console.log(data)
    }
</script>
// 函数定义要写在前面 不需要在这里调用函数 等另一个服务器返回函数调用
<script src="http://localhost:3001/test"></script> 

// s2服务器对应的服务器端代码
app.get('/test', (req, res) => {
    var result = 'fn({username: "zhangsan"})'
    res.send(result) // 将函数调用传递过去
})

优化1:将客户端定义的函数名字通过get参数的方式传递给服务器端 并在服务器端采用字符串拼接的方式进行传递 

// s1服务器对应的客户端代码
<script>
    function fn (data) {
        console.log('3000服务器的客户端被执行了')
        console.log(data)
    }
</script> // 函数定义要写在前面 不需要在这里调用函数 等另一个服务器返回函数调用
<script src="http://localhost:3001/better?callback=fn"></script> 
// s2服务器对应的服务器端代码
app.get('/better', (req, res) => {
    var funName = req.query.callback // 获取客户端传递过来的get参数
    var result = funName + '({username: "zhangsan"})'
    res.send(result) // 将函数调用传递过去
})

优化2:当点击按钮时再发送请求

// s1服务器对应的前端代码
<button id="btn">点击</button>

<script>
    function fn (data) {
        console.log('3000服务器的客户端被执行了')
        console.log(data)
    }
</script> // 函数定义要写在前面 不需要在这里调用函数 等另一个服务器返回函数调用
<script type="text/javascript">
    var btn = document.getElementById('btn')
    btn.onload = function () {
        var script = document.createElement('script)
        script.src = "http://localhost:3001/better?callback=fn"
        document.body.appendChild(script)
        script.onload = function () {
            document.body.removeChild(script)
        }
    }
</script>
// <script src="http://localhost:3001/better?callback=fn"></script> 

// s2服务器对应的服务器端代码
app.get('/better', (req, res) => {
    var funName = req.query.callback // 获取客户端传递过来的get参数
    var result = funName + '({username: "zhangsan"})'
    res.send(result) // 将函数调用传递过去
})

优化3:封装jsonp方法

// s1服务器对应的前端代码
<button id="btn">点击</button>

<script>
    function fn (data) {
        console.log('3000服务器的客户端被执行了')
        console.log(data)
    }
</script> // 函数定义要写在前面 不需要在这里调用函数 等另一个服务器返回函数调用
<script type="text/javascript">
    var btn = document.getElementById('btn')
    btn.onload = function () {
        jsonp({
            url: "http://localhost:3001/better?callback=fn"
        })
    }
    function jsonp (options) {
        var script = document.createElement('script)
        script.src = options.url
        document.body.appendChild(script)
        script.onload = function () {
            document.body.removeChild(script)
        }
    }
</script>

// s2服务器对应的服务器端代码
app.get('/better', (req, res) => {
    var funName = req.query.callback // 获取客户端传递过来的get参数
    var result = funName + '({username: "zhangsan"})'
    res.send(result) // 将函数调用传递过去
}) 


优化4:将处理函数与jsonp函数进行关联 同时自动生成函数名 支持传递多个参数

// s1服务器对应的前端代码
<button id="btn">点击</button>

<script type="text/javascript">
    var btn = document.getElementById('btn')
    btn.onload = function () {
        jsonp({
            url: "http://localhost:3001/better",
            data: {
                username: 'lisi',
                age: 20
            },
            success: function (data) {
                console.log('3000服务器的客户端被执行了')
                console.log(data)
            }
        })
    }
    function jsonp (options) {
        var script = document.createElement('script)
        // 拼接字符串
        var params = ''
        for (var attr in options.data) {
            params += '&' + attr + '=' + options.data[attr]
        }

        var funName = 'myJsonp' + Math.random().toString().replace('.', '') // 函数名不能是纯数字
        // options.success 客户端定义的函数应该是全局函数 所以将其挂载到window下
        // window.fn1 = options.success // 将函数变成全局函数 此时函数名固定 为fn1
        // script.src = options.url + '?callback=fn1'
        // 将函数名变成随机生成的 避免重复 如果重复 后调用的值会覆盖之前调用返回的值
        window[funName] = options.success // 将函数变成全局函数 变量不能用'.' 用'[]'调用或添加
        script.src = options.url + '?callback=' + funName + params
        document.body.appendChild(script)
        script.onload = function () {
            document.body.removeChild(script)
        }
    }
</script>

// s2服务器对应的服务器端代码
app.get('/better', (req, res) => {
    var funName = req.query.callback // 获取客户端传递过来的get参数
    var result = funName + '({username: "zhangsan"})' // 传递给send的是一个字符串
    res.send(result) // 将函数调用传递过去
}) 

优化4中还可对s2服务器对应的服务器端代码进行优化,总代码如下:

// s1服务器对应的前端代码
<button id="btn">点击</button>

<script type="text/javascript">
    var btn = document.getElementById('btn')
    btn.onload = function () {
        jsonp({
            url: "http://localhost:3001/better",
            data: {
                username: 'lisi',
                age: 20
            },
            success: function (data) {
                console.log('3000服务器的客户端被执行了')
                console.log(data)
            }
        })
    }
    function jsonp (options) {
        var script = document.createElement('script)
        // 拼接字符串
        var params = ''
        for (var attr in options.data) {
            params += '&' + attr + '=' + options.data[attr]
        }

        var funName = 'myJsonp' + Math.random().toString().replace('.', '') // 函数名不能是纯数字
        // options.success 客户端定义的函数应该是全局函数 所以将其挂载到window下
        // window.fn1 = options.success // 将函数变成全局函数 此时函数名固定 为fn1
        // script.src = options.url + '?callback=fn1'
        // 将函数名变成随机生成的 避免重复 如果重复 后调用的值会覆盖之前调用返回的值
        window[funName] = options.success // 将函数变成全局函数 变量不能用'.' 用'[]'调用或添加
        script.src = options.url + '?callback=' + funName + params
        document.body.appendChild(script)
        script.onload = function () {
            document.body.removeChild(script)
        }
    }
</script>

// s2服务器对应的服务器端代码
app.get('/better', (req, res) => {
    const funName = req.query.callback // 获取客户端传递过来的get参数
    const data = JSON.stringify({username: "zhangsan"})
    const result = funName + '(' + data + ')' // 传递给send的是一个字符串
    res.send(result) // 将函数调用传递过去 接收字符串 此时传递过去的是函数调用 客户端接收时参数就是对象格式就不需要再用JSON.parse()进行转换了
    // 如果是单纯传递一个字符串 在客户端调用时需要先将字符串转成json格式
})

2.CORS实现跨域资源共享,它允许浏览器向跨域服务器发送Ajax请求 克服了Ajax只能同源使用的限制

其基本实现原理为:

s1服务器对应的客户端正常向s2服务器发起ajax请求,s2服务器端设置请求头信息即可实现跨域请求

// s2服务器对应的服务器端代码
app.use((req, res, next) => {
    // 1.允许哪些客户端访问我
    // *代表允许所有的客户端访问我
    res.header('Access-Control-Allow-Origin', '*')
    // 2.允许客户端使用哪种请求方式访问我
    res.header('Access-Control-Allow-Methods', 'get, post')
    next()
})

3.访问非同源数据 服务器端解决方案

同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策的限制,s1网站的客户端向s1服务器端发送数据请求,然后s1服务器向s2服务器发送数据请求,最后s1服务器将获取到的数据再响应给s1网站的客户端。

1.s1网站的客户端正常向s1服务器端发送ajax请求,并在s1服务器端安装request模块,命令为: npm install request

s1网站的服务器端:

const request = require('request')
app.get('/server', (req, res) => {
    request('http://localhost:3001/cross', (err, response, body) => {
        res.send(body) // 向http://localhost:3001/cross发送请求 body为s2服务器端返回的数据
    })
})

s2网站的服务器端:

app.get('/cross', (req, res) => {
    res.send('ok')
})

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值