同源策略
同源策略是浏览器的一种安全策略,所谓同源指的是请求URL地址中的协议、域名和端口号都相同,只要其中之一不相同就是跨域。
同源策略主要是为了保证浏览器的安全性
在同源策略下,浏览器不允许Ajax跨域获取服务器数据
说简单点:跨域是指从一个域名的网页去请求另一个域名的资源。只要协议、域名、端口有任何一个的不同,就被当作是跨域。
跨域的本质
Ajax 是为了访问自己服务器的数据,跨域是为了访问别人服务器的数据
跨域的本质:服务器返回了一个方法调用,这个方法是我们事先定义好的,而方法中的参数就是我们想要的数据。即script引入外部文件,这个文件的内容就是一个方法调用
引入外部 JS 文件
引入外部 php 文件
同理
动态创建 script 标签
// cityName 指动态输入的值
let cityName = document.querySelector("#city").value;
//动态创建script标签,动态制定src属性的值
let script = document.createElement("script");
script.src = "http://www.lisi.com/data.php?city=" + cityName;
let head = document.querySelector("head");
head.appendChild(script);
data.php 页面
<?php
$city = $_GET["city"];
if($city == "beijing") {
echo "foo('北京的天气晴')";
}else {
echo "foo('没有查询到天气信息')";
}
?>
test.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript">
function foo(data){
console.log(data);
}
</script>
<script type="text/javascript">
window.onload = function(){
let btn = document.querySelector("#btn");
btn.onclick = function(){
let cityName = document.querySelector("#city").value;
//动态创建script标签,动态制定src属性的值
let script = document.createElement("script");
script.src = "http://www.lisi.com/data.php?city="+cityName;
let head = document.querySelector("head");
head.appendChild(script);
};
};
</script>
</head>
<body>
<h1>天气信息查询</h1>
<input type="text" id="city" placeholder="请输入城市名称">
<!-- <button id="btn">查询</button> -->
<input type="button" id="btn" value="查询">
</body>
</html>
动态指定回调函数名称(前端界面决定方法名称)
<?php
$cbName = $_GET["callback"];
$city = $_GET["city"];
// 将方法名用.进行字符串的连接
if($city == "beijing") {
echo $cbName."('北京的天气晴')";
}else {
echo $cbName."('没有查询到天气信息')";
}
?>
test.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
// 等待 data.php 返回具体内容的调用
<script type="text/javascript">
function foo(data){
console.log(data);
}
</script>
<script type="text/javascript">
window.onload = function(){
let btn = document.querySelector("#btn");
btn.onclick = function(){
let cityName = document.querySelector("#city").value;
//动态创建script标签,动态制定src属性的值
let script = document.createElement("script");
script.src = "http://www.lisi.com/data.php?city="+cityName;
let head = document.querySelector("head");
head.appendChild(script);
};
};
</script>
</head>
<body>
<h1>天气信息查询</h1>
<input type="text" id="city" placeholder="请输入城市名称">
<!-- <button id="btn">查询</button> -->
<input type="button" id="btn" value="查询">
</body>
</html>
给 window 增加属性进行方法定义
优化 test.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- <script type="text/javascript">
function foo(data){
console.log(data);
}
</script> -->
<script type="text/javascript">
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var cityName = document.querySelector("#city").value;
//动态创建script标签,动态制定src属性的值
var script = document.createElement("script");
script.src = "http://www.lisi.com/data.php?city=" + cityName + "&callback=foo";
// 给 window 增加了一个属性 foo ,这个属性是一个方法
window["foo"] = function(data) {
console.log(data);
};
var head = document.querySelector("head");
head.appendChild(script);
};
};
</script>
</head>
<body>
<h1>天气信息查询</h1>
<input type="text" id="city" placeholder="请输入城市名称">
<button id="btn">查询</button>
</body>
</html>
【淘宝提示词案例】
地址:https://suggest.taobao.com/sug
taobao_sug 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript">
window.onload = function() {
let btn = document.querySelector("#btn");
btn.onclick = function() {
let keywordValue = document.querySelector("#keyword").value;
console.log(keywordValue);
let script = document.createElement("script");
script.src = "https://suggest.taobao.com/sug?q=" + keywordValue + "&callback=fn1";
window["fn1"] = function(data) {
let liTag = "";
for (let i = 0; i < data.result.length; i++) {
let temp = data.result[i];
let tempSug = temp[0];
liTag += "<li>" + tempSug + "</li>";
}
let ulTag = document.querySelector("ul");
ulTag.innerHTML = liTag;
};
let head = document.querySelector("head");
head.appendChild(script);
};
};
</script>
</head>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<button id="btn">查询</button>
<ul>
<!-- <li>1</li> -->
</ul>
</body>
</html>
演示图
【百度提示词案例】
地址:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su
baidu_sug.html 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript">
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var keywordValue = document.querySelector("#keyword").value;
console.log(keywordValue);
var script = document.createElement("script");
script.src = "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=" + keywordValue + "&cb=fn1";
window["fn1"] = function(data) {
var liTag = "";
for (var i = 0; i < data.s.length; i++) {
var temp = data.s[i];
liTag += "<li>" + temp + "</li>";
}
var ulTag = document.querySelector("ul");
ulTag.innerHTML = liTag;
};
var head = document.querySelector("head");
head.appendChild(script);
};
};
</script>
</head>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<button id="btn">查询</button>
<ul>
<!-- <li>1</li> -->
</ul>
</body>
</html>
自定义封装获取跨域数据
myajax.js
function myAjax(obj){
let defaults = {
type:"get",
url:"#",
data:{},
success:function(data){},
jsonp:"callback",
jsonpCallback:"fn1"
};
for(let key in obj) {
defaults[key] = obj[key];
}
let params = "";
for(let attr in defaults.data){
params += attr + "=" + defaults.data[attr] + "&";
}
if(params) {
params = params.substring(0,params.length-1);
defaults.url += "?" + params;
}
defaults.url += "&"+defaults.jsonp+"=" + defaults.jsonpCallback;
console.log(defaults.url);
let script = document.createElement("script");
script.src = defaults.url;
window[defaults.jsonpCallback] = function(data){
defaults.success(data);
};
let head = document.querySelector("head");
head.appendChild(script);
}
修改后的百度提示词案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="myajax.js"></script>
<script type="text/javascript">
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var keywordValue = document.querySelector("#keyword").value;
// console.log(keywordValue);
myAjax({
url: "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
data: {
wd: keywordValue
},
success: function(data) {
console.log(data);
},
jsonp: "cb",
// jsonpCallback: "haha"
});
};
};
</script>
</head>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<button id="btn">查询</button>
<ul>
<!-- <li>1</li> -->
</ul>
</body>
</html>
使用 jQuery 获取跨域数据
dataType:"jsonp"
:一定要是 jsonp 格式
key 默认就是 callback
$.ajax({
url: "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
data: {
wd: keywordValue
},
success: function(data) {
console.log(data);
},
dataType: "jsonp",
jsonp: "cb"
});
完善 myAjax() 方法
既可获取同源的数据,也可以获取跨域的数据。
function myAjax(obj){
if(obj.dataType == "jsonp") {
myAjax_Across(obj);
} else {
myAjax_Normal(obj);
}
}
// 跨域获取数据
function myAjax_Across(obj){
let defaults = {
type:"get",
url:"#",
data:{},
success:function(data){},
jsonp:"callback",
jsonpCallback:"fn1"
};
for(let key in obj) {
defaults[key] = obj[key];
}
let params = "";
for(let attr in defaults.data){
params += attr + "=" + defaults.data[attr] + "&";
}
if(params) {
params = params.substring(0,params.length-1);
defaults.url += "?" + params;
}
defaults.url += "&"+defaults.jsonp+"=" + defaults.jsonpCallback;
console.log(defaults.url);
let script = document.createElement("script");
script.src = defaults.url;
window[defaults.jsonpCallback] = function(data){
defaults.success(data);
};
let head = document.querySelector("head");
head.appendChild(script);
}
// 正常获取数据
function myAjax_Normal(obj) {
let defaults = {
type: "get",
url: "#",
dataType: "json",
data: {},
async: true,
success: function(result) {
console.log(result);
}
};
//obj中的属性,覆盖到defaults中的属性
//1、如果有一些属性只存在obj中,会给defaults中增加属性
//2、如果有一些属性在obj和defaults中都存在,会将defaults中的默认值覆盖
//3、如果有一些属性只在defaults中存在,在obj中不存在,这时候defaults中将保留预定义的默认值
for (let key in obj) {
defaults[key] = obj[key];
}
// 创建对象
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//得到params
// data:{
// uname:"zhangsan",
// age:"18"
// }// uname=zhangsan&age=18
let params = "";
for (let attr in defaults.data) {
params += attr + "=" + defaults.data[attr] + "&";
}
if (params) {
params = params.substring(0, params.length - 1);
}
if (defaults.type == "get") {
defaults.url += "?" + params;
}
// 准备发送
xhr.open(defaults.type, defaults.url, defaults.async);
// 执行发送
if (defaults.type == "get") {
xhr.send(null);
} else if (defaults.type == "post") {
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(params);
}
// 判断是否为异步
if (defaults.async) {
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
let result = null;
if (defaults.dataType == "json") {
result = xhr.responseText;
result = JSON.parse(result);
} else if (defaults.dataType == "xml") {
result = xhr.responseXML;
} else {
result = xhr.responseText;
}
defaults.success(result);
}
}
};
} else {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
let result = null;
if (defaults.dataType == "json") {
result = xhr.responseText;
result = JSON.parse(result);
} else if (defaults.dataType == "xml") {
result = xhr.responseXML;
} else {
result = xhr.responseText;
}
defaults.success(result);
}
}
}
}