欢迎学习交流!!!
持续更新中…
如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。
同源政策的目的:
同源政策是为了保护用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指A网站在客户端设置的Cookie,B网站是不能访问的
随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax请求,如果请求,浏览器就会报错。
使用JSONP解决同源限制问题,该方式实际上已经不属于ajax请求的范围,但是可以模拟出ajax的请求效果,该方式就是绕过浏览器的同源政策限制,向非同源服务器端发送请求。
jsonp是json with padding的缩写(实际上指在服务器端将json数据作为填充内容/函数的参数,将json数据填充到函数中去),它不属于Ajax请求,但它可以模拟Ajax请求
使用JSONP解决同源限制问题的基本步骤:
<script src="www.example.com"></script>
//请求地址可以是任意形式,不是必须以.js结尾的,但必须返回合法的js代码
可以利用script的src属性中可以写线上的jquery文件地址,为典型的向非同源的服务器端请求数据的案例。
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
const data = 'fn({name: "张三", age: "17"})';
res.send(data);
function fn (data) {
}
function fn (data) {
console.log(data); }
例:
客户端:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script>
function fn() {
console.log('客户端的fn函数被调用了')
}
script>
<script src="http://localhost:3001/test">script>
body>
html>
在另外一个,3001服务器中的app.js文件:
<!-- 2号服务器的app.js -->
<script>
// 引入express框架
const express = require('express');
// 路径处理模块
const path = require('path');
// 创建网站服务器
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/test',(req, res) => {
//函数调用应该在服务器端进行调用,只需要服务器端写出函数调用的字符串,若在此处直接调用,则前后没有函数定义的代码,就会报错
const result = 'fn()';
res.send(result)
})
</script>
虽然现在请求能够被发送,也能够获取服务器端响应的数据,但是请求是在页面加载的过程中被发送的,即请求是在访问html页面的时候被立即发送的,而不是请求在想发送的时候立即发送的(如点击按钮时)。
客户端:
<script>
function fn2 (data) {
console.log('客户端的fn函数被调用了')
console.log(data);
}
</script>
<!-- 将非同源服务器段的请求地址写在script标签的src属性中 -->
<script src="http://localhost:3001/better?callback=fn2"></script>
服务器端:2号服务器端 app.js文件
const express = require('express');
const path = require('path');
const app = express();
// 静态资源访问服务功能
app.use(express.static(path.join(__dirname,'public')));
app.get('/brtter', (req,res) => {
//接收客户端传递过来的函数名称
const fnName = req.query.callback;
// 将函数名称对应的函数调用代码返回给客户端
const result = fnName + '({name: "张三"})';
res.send(result);
})
// 监听端口
app.listen(3001);
// 控制台提示输出
console.log('服务器启动成功');
<button id="btn">点我发送请求button>
<script>
function fn2 (data) {
console.log('客户端的fn函数被调用了')
console.log(data);
}
script>
<script type="text/javascript">
// 获取按钮
var btn = document.getElementById('btn');
// 为按钮添加点击事件
btn.onclick = function () {
// 动态创建script标签
var script = document.createElement('script');
// 为script标签添加设置src属性
script.src = 'http://localhost:3001/better?callback=fn2';
// 将srcipt标签追加到页面中
document.body.appendChild(script);
// 为script标签添加onload事件
script.onload = function () {
// 将body中的script标签删除掉
document.body.removeChild(script);
}
}
script>
<button id="btn">点我发送请求button>
<script>
function fn2 (data) {
console.log('客户端的fn函数被调用了');
console.log(data);
}
script>
<script type="text/javascript">
// 获取按钮
var btn = document.getElementById('btn');
// 为按钮添加点击事件
btn.onclick = function () {
jsonp({
//当前对象为jsonp属性的实参,而在函数定义的时候有一个形参与之对应---options
// 请求地址
url: 'http://localhost:3001/better?callback=fn2'
})
}
// 当想向非同源服务器发送请求时只需要调用jsonp函数即可
function jsonp (options) {
// 动态创建script标签
var script = document.createElement('script');
// 为script标签添加src属性 只有在发送请求,调用jsonp函数的时才会知道请求会发送到哪里去
script.src = options.url;
// 将script标签追加到页面中,这样请求才能发送出去
document.body.appendChild(script);
// 为script标签添加onload事件
script.onload = function () {
document.body.removeChild(script);
}
}
script>
虽然已经封装jsonp函数用于发送请求,但在函数外部的其他地方还需要另外定义一个函数用于接收服务器端的返回数据:
<button id="btn">点我发送请求button>
<script>
function fn2 (data) {
console.log('客户端的fn函数被调用了');
console.log(data);
}
script>
<script type="text/javascript">
// 获取按钮
var btn = document.getElementById('btn');
// 为按钮添加点击事件
btn.onclick = function () {
jsonp({
//当前对象为jsonp属性的实参,而在函数定义的时候有一个形参与之对应---options
// 请求地址
url: 'http://localhost:3001/better',
success: function (data) {
console.log(777);
console.log(data);
}
})
}
// 当想向非同源服务器发送请求时只需要调用jsonp函数即可
function jsonp (options) {
// 动态创建script标签
var script = document.createElement('script');
// rendom()产生0-9之间的随机小数-->需要去掉小数点 函数名:myJsonp0898789
var fnName = 'myJsonp' + Math.rendom().toString().replace('.','')
// 它已经不是一个全局函数,服务器在返回函数调用时找不到该函数
// 因此要想办法将其变成一个全局函数(在JS中window代表全局)
window[fnName] = options.success; //函数名字不能固定,否则连续发送请求时会覆盖掉
// 为script标签添加src属性 只有在发送请求,调用jsonp函数的时才会知道请求会发送到哪里去
script.src = options.url + '?callback=' + fnName;
// 将script标签追加到页面中,这样请求才能发送出去
document.body.appendChild(script);
// 为script标签添加onload事件
script.onload = function () {
document.body.removeChild(script);
}
}
script>
完善:在发送请求时目前只是传递了一个callback参数,若该请求要求传递更多参数时,则就和ajax函数一样,在调用jsonp函数的时候传递一个data属性,属性的值为一个对象,对象中存储的就是想要向服务器端发送的请求参数,在jsonp函数内部,要讲对象转换为‘参数名称=参数值’,多个参数之间用‘&’隔开的字符串
// 获取按钮
var btn = document.getElementById('btn');
// 为按钮添加点击事件
btn.onclick = function () {
jsonp({
//当前对象为jsonp属性的实参,而在函数定义的时候有一个形参与之对应---options
// 请求地址
url: 'http://localhost:3001/better',
data: {
name: '王五',
age: 17
},
success: function (data) {
console.log(777);
console.log(data);
}
})
}
// 当想向非同源服务器发送请求时只需要调用jsonp函数即可
function jsonp (options) {
// 动态创建script标签
var script = document.createElement('script');
// 拼接字符串的变量
var params = '';
for (var attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
// rendom()产生0-9之间的随机小数-->需要去掉小数点 函数名:myJsonp0898789
var fnName = 'myJsonp' + Math.rendom().toString().replace('.','')
// 它已经不是一个全局函数,服务器在返回函数调用时找不到该函数
// 因此要想办法将其变成一个全局函数(在JS中window代表全局)
window[fnName] = options.success; //函数名字不能固定,否则连续发送请求时会覆盖掉
// 为script标签添加src属性 只有在发送请求,调用jsonp函数的时才会知道请求会发送到哪里去
script.src = options.url + '?callback=' + fnName + params;
// 将script标签追加到页面中,这样请求才能发送出去
document.body.appendChild(script);
// 为script标签添加onload事件
script.onload = function () {
document.body.removeChild(script);
}
}