初始前后端交互+原生Ajax+Fetch+axios+同源策略+解决跨域
- [1 初识前后端交互](#1 初识前后端交互)
- [2 原生Ajax](#2 原生Ajax)
-
- [2.1 Ajax基础](#2.1 Ajax基础)
- [2.2 Ajax案例](#2.2 Ajax案例)
- [2.3 ajax请求方式](#2.3 ajax请求方式)
- [3 Fetch](#3 Fetch)
-
- [3.1 fetch基础](#3.1 fetch基础)
- [3.2 fetch案例](#3.2 fetch案例)
- [4 axios](#4 axios)
-
- [4.1 axios基础](#4.1 axios基础)
- [4.2 axios使用](#4.2 axios使用)
-
- [4.2.1 axios拦截器](#4.2.1 axios拦截器)
- [4.2.2 axios中断器](#4.2.2 axios中断器)
- [5 同源策略](#5 同源策略)
- [6 解决跨域](#6 解决跨域)
-
- [6.1 jsonp](#6.1 jsonp)
- [6.2 其他技术手段](#6.2 其他技术手段)
1 初识前后端交互
- 传统网站的问题:
1> 为了获取数据,需要重新加载,浪费资源,增加等待时间,性能不好。
2> 验证表单过程中,一项内容不合格,页面需要重新加载,体验不好。 - 解决问题:
1> ajax 全名 async javascript and XML
2> 是前后台交互的能力
3> 也就是我们客户端给服务端发送消息的工具,以及接受响应的工具
4> 是一个默认异步执行机制的功能 - AJAX的优势:
1> 不需要插件的支持,原生 js 就可以使用
2> 用户体验好(不需要刷新页面就可以更新数据)
3> 减轻服务端和带宽的负担
4> 缺点: 搜索引擎的支持度不够,因为数据都不在页面上,搜索引擎搜索不到
2 原生Ajax
2.1 Ajax基础
- 在 js 中有内置的构造函数来创建 ajax 对象;
javascript
const xhr = new XMLHttpRequest()
// 上面就是有了一个 ajax 对象
// 我们就可以使用这个 `xhr` 对象来发送 ajax 请求了
- 配置链接信息;
javascript
xhr.open("get","1.json ",true)
// xhr.open('请求方式', '请求地址', 是否异步)
// xhr 对象中的 open 方法是来配置请求信息的
// 第一个参数是本次请求的请求方式 get / post / put / ...
// 第二个参数是本次请求的 url
// 第三个参数是本次请求是否异步,默认 true 表示异步,false 表示同步
- 创建 ajax 对象以后,我们就使用 ajax 对象的方法去发送请求和接受响应。
javascript
xhr.send()
// 使用 xhr 对象中的 send 方法来发送请求
// 上面代码是把配置好信息的 ajax 对象发送到服务端
一、一个基本的ajax请求:
一个最基本的 ajax 请求就是上面三步
但是光有上面的三个步骤,我们确实能把请求发送的到服务端
如果服务端正常的话,响应也能回到客户端,但是我们拿不到响应
如果想拿到响应,我们有两个前提条件:
1. 本次 HTTP 请求是成功的,也就是我们之前说的 http 状态码为 200 ~ 299
2. ajax 对象也有自己的状态码,用来表示本次 ajax 请求中各个阶段
二、ajax 状态码:
ajax 状态码 ------ xhr.readyState
是用来表示一个 ajax 请求的全部过程中的某一个状态
readyState === 0: 表示未初始化完成,也就是 `open` 方法还没有执行
readyState === 1: 表示配置信息已经完成,也就是执行完 `open` 之后
readyState === 2: 表示 `send` 方法已经执行完成
readyState === 3: 表示正在解析响应内容
readyState === 4: 表示响应内容已经解析完毕,可以在客户端使用了
这个时候我们就会发现,当一个 ajax 请求的全部过程中,只有当 `readyState === 4` 的时候,我们才可以正常使用服务端给我们的数据
所以,配合 http 状态码为 200 ~ 299
一个 ajax 对象中有一个成员叫做 `xhr.status`
这个成员就是记录本次请求的 http 状态码的
两个条件都满足的时候,才是本次请求正常完成
三、readyStateChange
在 ajax 对象中有一个事件,叫做 `readyStateChange` 事件
这个事件是专门用来监听 ajax 对象的 `readyState` 值改变的的行为
也就是说只要 `readyState` 的值发生变化了,那么就会触发该事件
所以我们就在这个事件中来监听 ajax 的 `readyState` 是不是到 4 了
四、responseText
ajax 对象中的 `responseText` 成员
就是用来记录服务端给我们的响应体内容的
所以我们就用这个成员来获取响应体内容就可以
html
<!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>Document</title>
</head>
<body>
<button>aaa</button>
<script>
var xhr = new XMLHttpRequest()
xhr.open("get","1.json ",true)
// 第一个参数 get post 请求方式
// 第二个参数 请求地址
// 第三个参数 是否异步
xhr.send()
// 监听
// 方法一
/* xhr.onreadystatechange = function() {
console.log("电话接通");
console.log(xhr.readyState); // 准备状态
if(xhr.readyState === 4) {
// if(xhr.status === 200) {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
} */
// 方法二
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
</script>
</body>
</html>
json
{
"name":"xiaowang"
}
2.2 Ajax案例
html
<!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>Document</title>
</head>
<body>
<button id="btn">click</button>
<ul id="list">
</ul>
<script>
var obtn = document.querySelector('#btn')
var olist = document.querySelector('#list')
obtn.onclick = function() {
var xhr = new XMLHttpRequest()
xhr.open("get","http://www.xiongmaoyouxuan.com/api/tabs", true) // 后端接口地址
xhr.send()
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
// console.log(JSON.parse(xhr.responseText))
render(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
}
// 渲染页面
function render(res) {
console.log(res.data.list);
var newlist = res.data.list.map(function(item){
return `<li>
<img src="${item.imageUrl}"/>
<div>${item.name}</div>
</li>`
})
console.log(newlist);
olist.innerHTML = newlist.JSON.join("")
}
</script>
</body>
</html>
json
{
"data": {
"list": [
{
"name": "假数据111",
"imageUrl": "http://img1.lukou.com/static/p/fb/tab/1/20181211-151644.jpeg"
},
{
"name": "假数据222",
"imageUrl": "http://img1.lukou.com/static/p/fb/tab/1/20181211-151644.jpeg"
},
{
"name": "假数据111",
"imageUrl": "http://img1.lukou.com/static/p/fb/tab/1/20181211-151644.jpeg"
},
{
"name": "假数据111",
"imageUrl": "http://img1.lukou.com/static/p/fb/tab/1/20181211-151644.jpeg"
}
]
}
}
2.3 ajax请求方式
-
不同的请求方式:
1> get 偏向获取
2> post 偏向提交
3> put 偏向更新
4> patch 偏向修改部分
5> delete 偏向删除信息
6> head 偏向获取服务器头的信息
7> option 偏向获取服务器设备信息
8> connect 保留请求方式
-
使用get请求方式(不传参数):
javascript
oget.onclick = function() {
var xhr = new XMLHttpRequest()
xhr.open("GET","http://localhost:3000/list", true) // 后端接口地址
xhr.send()
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
// render(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
}
- 使用get请求方式(传参数):
javascript
oget.onclick = function() {
var xhr = new XMLHttpRequest()
xhr.open("GET","http://localhost:3000/users?id=1", true)
xhr.send()
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
// render(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
}
- 使用post请求方式(传参数):
javascript
opost.onclick = function() {
var xhr = new XMLHttpRequest()
xhr.open("POST","http://localhost:3000/users", true) // 后端接口地址
// 两种提交方式:
// form编码 name=kerwin&age=100
// json {name:"kerwin",age:100}
// 方式一
/* xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")
xhr.send(`name=tiechui&age=18`) */ // 数据放在这里
// 方式二
xhr.setRequestHeader("content-type","application/json")
xhr.send(JSON.stringify({
name:"guludunzi",
age:90
})) // 数据放在这里
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
// render(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
}
- 使用put请求方式(传参数):
javascript
oput.onclick = function() {
var xhr = new XMLHttpRequest()
xhr.open("PUT","http://localhost:3000/users/4", true) // 后端接口地址
// 两种提交方式:
// form编码 name=kerwin&age=100
// json {name:"kerwin",age:100}
// 方式一
/* xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")
xhr.send(`name=tiechui&age=18`) */ // 数据放在这里
// 方式二
xhr.setRequestHeader("content-type","application/json")
xhr.send(JSON.stringify({
username:"guludunzi",
age:70
})) // 数据放在这里
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
// render(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
}
- 使用patch请求方式(传参数):
javascript
opatch.onclick = function() {
var xhr = new XMLHttpRequest()
xhr.open("PATCH","http://localhost:3000/users/4", true) // 后端接口地址
// 两种提交方式:
// form编码 name=kerwin&age=100
// json {name:"kerwin",age:100}
// 方式一
/* xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")
xhr.send(`name=tiechui&age=18`) */ // 数据放在这里
// 方式二
xhr.setRequestHeader("content-type","application/json")
xhr.send(JSON.stringify({
// username:"guludunzi",
age:180
})) // 数据放在这里
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
// render(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
}
- 使用delete请求方式(无参数):
javascript
odelete.onclick = function() {
var xhr = new XMLHttpRequest()
xhr.open("DELETE","http://localhost:3000/users/4", true) // 后端接口地址
xhr.send()
xhr.onload = function() {
if(/^2\d{2}$/.test(xhr.status)) {
console.log(JSON.parse(xhr.responseText))
// render(JSON.parse(xhr.responseText))
} else {
console.log("error",xhr.responseText);
}
}
}
3 Fetch
- XMLHttpRequest 是一个设计粗糙的 API,配置和调用方式非常混乱, 而且基于事件的异步模型写起来不友好。
- 先在集成终端中打开json-server监视:
3.1 fetch基础
- 使用get请求方式(不传参数):
javascript
oget.onclick = function() {
fetch("http://localhost:3000/users")
.then(res =>res.json())
.then(res => {
console.log(res);
})
}
- 使用get请求方式(传参数):
javascript
oget.onclick = function() {
fetch("http://localhost:3000/users?id=1")
.then(res =>res.json())
.then(res => {
console.log(res);
})
}
- 使用post请求方式(传参数):
javascript
opost.onclick = function() {
fetch("http://localhost:3000/users",{
method:"post",
headers:{
// 两种提交方式:
// form编码 name=kerwin&age=100
// json {name:"kerwin",age:100}
// 方式一
// "content-type":"application/x-www-form-urlencoded"
// 方式二
"content-type":"application/json"
},
// body:"name=dazhuang&age=100" // 方式一body
body:JSON.stringify({
name:"xiaoli",
age: 20
})
})
.then(res =>res.json())
.then(res => {
console.log(res);
})
}
- 使用put请求方式(传参数):
javascript
oput.onclick = function() {
fetch("http://localhost:3000/users/2",{
method:"put",
headers:{
// 两种提交方式:
// form编码 name=kerwin&age=100
// json {name:"kerwin",age:100}
// 方式一
// "content-type":"application/x-www-form-urlencoded"
// 方式二
"content-type":"application/json"
},
// body:"name=dazhuang&age=100" // 方式一body
body:JSON.stringify({
name:"xiaowang",
age: 76
})
})
.then(res =>res.json())
.then(res => {
console.log(res);
})
}
- 使用patch请求方式(传参数):
javascript
opatch.onclick = function() {
fetch("http://localhost:3000/users/2",{
method:"PATCH",
headers:{
// 两种提交方式:
// form编码 name=kerwin&age=100
// json {name:"kerwin",age:100}
// 方式一
// "content-type":"application/x-www-form-urlencoded"
// 方式二
"content-type":"application/json"
},
// body:"name=dazhuang&age=100" // 方式一body
body:JSON.stringify({
age: 33
})
})
.then(res =>res.json())
.then(res => {
console.log(res);
})
}
- 使用delete请求方式(无参数):
javascript
odelete.onclick = function() {
fetch("http://localhost:3000/users/2",{
method:"delete",
})
.then(res =>res.json())
.then(res => {
console.log(res);
})
}
- 以使用get请求方式为例失败处理:
javascript
oget.onclick = function() {
fetch("http://localhost:3000/users?id=1")
.then(res =>{
if(res.ok){
return res.json()
}else{
return Promise.reject({
// 展示出错码和出错原因
status:res.status,
statusText:res.statusText
})
}
})
.then(res => {
console.log(res);
}).catch(err => {
console.log("err", err)
})
}
3.2 fetch案例
- 通过输入作者姓名找到新闻标题,再根据新闻标题对应的新闻id找到所对应的评论内容。
- db.json代码:
json
{
"news": [
{ "id" : 1, "title" : "男人看了沉默,女人看了流泪", "author" : "kerwin"},
{ "id" : 2, "title" : "震惊!他年薪仅1元", "author" : "tiechui"},
{ "id" : 3, "title" : "速看!万分危急!", "author" : "gangdan"}
],
"comments": [
{ "id" : 1, "body" : "我是男人", "newsId" : 1 },
{ "id" : 2, "body" : "我是女人", "newsId" : 1 },
{ "id" : 3, "body" : "我年薪2元", "newsId" : 2 },
{ "id" : 4, "body" : "我年薪3元", "newsId" : 2 },
{ "id" : 5, "body" : "1块钱就能买1块钱的东西", "newsId" : 3 },
{ "id" : 6, "body" : "2块钱就能买2块钱的东西", "newsId" : 3 }
]
}
- 基于fetch的01.html代码:
html
<!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>Document</title>
</head>
<body>
<input type="text" id="search">
<h1 id="title"></h1>
<ul id="list"></ul>
<script>
var osearch = document.querySelector('#search')
var otitle = document.querySelector('#title')
var olist = document.querySelector('#list')
osearch.oninput = function() {
fetch(`http://localhost:3000/news?author=${osearch.value}`)
.then( res => res.json())
.then( res => {
if(res.length > 0) {
otitle.innerHTML = res[0].title
return fetch(`http://localhost:3000/comments?newsId=${res[0].id}`)
.then(res=>res.json())
}else {
otitle.innerHTML = ""
return res
}
}).then(res=>{
console.log(res)
olist.innerHTML = res.map( item => `
<li>
${item.body}
</li>
`).join("") // join是为了避免中间有逗号
})
}
</script>
</body>
</html>
- fetch结合async await下的01.html代码:
html
<!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>Document</title>
</head>
<body>
<input type="text" id="search">
<h1 id="title"></h1>
<ul id="list"></ul>
<script>
var osearch = document.querySelector('#search')
var otitle = document.querySelector('#title')
var olist = document.querySelector('#list')
osearch.oninput = async function() {
var res = await fetch(`http://localhost:3000/news?author=${osearch.value}`)
.then( res => res.json())
var result
if(res.length > 0) {
otitle.innerHTML = res[0].title
result = await fetch(`http://localhost:3000/comments?newsId=${res[0].id}`)
.then(res=>res.json())
}else {
otitle.innerHTML = ""
result = res
}
// console.log("111",result)
olist.innerHTML = result.map( item => `
<li>
${item.body}
</li>
`).join("") // join是为了避免中间有逗号
}
</script>
</body>
</html>
4 axios
- Axios是一个基于promise 的 HTTP 库,可以用在浏览器和 node.js中。
- https://www.npmjs.com/package/axios
4.1 axios基础
- 使用get请求方式(不传参数):
javascript
oget.onclick = function() {
axios.get("http://localhost:3000/users")
// 若成功走.then
.then(res => {
console.log(res.data)
})
// 若失败走.catch
.catch(err => {
console.log("err",err)
})
}
- 使用get请求方式(传参数):
javascript
oget.onclick = function() {
axios.get("http://localhost:3000/users?name=kerwin")
// 若成功走.then
.then(res => {
console.log(res.data)
})
// 若失败走.catch
.catch(err => {
console.log("err",err)
})
}
- 使用get请求方式(传参数且为对象结构):
javascript
oget.onclick = function() {
axios.get("http://localhost:3000/users",{
params:{
name:"kerwin"
}
})
// 若成功走.then
.then(res => {
console.log(res.data)
})
// 若失败走.catch
.catch(err => {
console.log("err",err)
})
}
- 使用post请求方式(传参数):
javascript
opost.onclick = function() {
// 以json方式传参数
/* axios.post("http://localhost:3000/users",{
name:"xiaoming",
age:18
}) */
// 以form方式传参数方法一
// axios.post("http://localhost:3000/users","name=tiechui&age=77")
// 以form方式传参数方法二
const params = new URLSearchParams({name:"dazhuang",age:13});
axios.post("http://localhost:3000/users",params)
// 若成功走.then
.then(res => {
console.log(res.data)
})
// 若失败走.catch
.catch(err => {
console.log("err",err)
})
}
- 使用put请求方式(传参数):
javascript
oput.onclick = function() {
axios.put("http://localhost:3000/users/4",{
name:"dazhuang",
age:99
})
// 若成功走.then
.then(res => {
console.log(res.data)
})
// 若失败走.catch
.catch(err => {
console.log("err",err)
})
}
- 使用patch请求方式(传参数):
javascript
opatch.onclick = function() {
axios.patch("http://localhost:3000/users/4",{
age:101
})
// 若成功走.then
.then(res => {
console.log(res.data)
})
// 若失败走.catch
.catch(err => {
console.log("err",err)
})
}
- 使用delete请求方式(无参数):
javascript
odelete.onclick = function() {
axios.delete("http://localhost:3000/users/4")
// 若成功走.then
.then(res => {
console.log(res.data)
})
// 若失败走.catch
.catch(err => {
console.log("err",err)
})
}
- axios(config)配置:
javascript
axios({
method:"post",
url:'http://localhost:3000/users',
// put post等放入data中 get放入params中
data:{
name:'kerwin',
age: 88
}
})
.then(res => {
console.log(res.data)
})
.catch(err => {
console.log(err)
})
4.2 axios使用
4.2.1 axios拦截器
- db.json代码:
json
{
"news": [
{ "id" : 1, "title" : "男人看了沉默,女人看了流泪", "author" : "kerwin"},
{ "id" : 2, "title" : "震惊!他年薪仅1元", "author" : "tiechui"},
{ "id" : 3, "title" : "速看!万分危急!", "author" : "gangdan"}
],
"comments": [
{ "id" : 1, "body" : "我是男人", "newsId" : 1 },
{ "id" : 2, "body" : "我是女人", "newsId" : 1 },
{ "id" : 3, "body" : "我年薪2元", "newsId" : 2 },
{ "id" : 4, "body" : "我年薪3元", "newsId" : 2 },
{ "id" : 5, "body" : "1块钱就能买1块钱的东西", "newsId" : 3 },
{ "id" : 6, "body" : "2块钱就能买2块钱的东西", "newsId" : 3 }
]
}
- 01.html代码:
html
<!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>Document</title>
<!-- 引入axios -->
<script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
</head>
<body>
<button id="get">get</button>
<script>
var oget = document.querySelector("#get")
// axios拦截器
// request请求拦截器
axios.interceptors.request.use(function (config) {
// Do something before request is sent
// console.log("loading-开始")
console.log("loading显示....")
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// response响应拦截器
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
// 成功响应拦截器
// console.log("loading-结束")
console.log("成功-隐藏loading....")
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
// 失败响应拦截器
// console.log("loading---结束")
console.log("失败-隐藏loading....")
return Promise.reject(error);
});
oget.onclick = function() {
axios.get('http://localhost:3000/news').then(res => {
console.log(res.data);
}).catch(err => {
console.log("err",err);
})
}
</script>
</body>
</html>
4.2.2 axios中断器
javascript
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// cancel the request
controller.abort()
- 01.html代码:
html
<!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>Document</title>
<!-- 引入axios -->
<script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
</head>
<body>
<button id="get">get</button>
<!-- 终止按钮 -->
<button id="abort">abort</button>
<script>
var oget = document.querySelector("#get")
var oabort = document.querySelector("#abort")
// axios拦截器
// request请求拦截器
axios.interceptors.request.use(function (config) {
// Do something before request is sent
// console.log("loading-开始")
console.log("loading显示....")
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// response响应拦截器
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
// 成功响应拦截器
// console.log("loading-结束")
console.log("成功-隐藏loading....")
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
// 失败响应拦截器
// console.log("loading---结束")
console.log("失败-隐藏loading....")
return Promise.reject(error);
});
// axios中断器
const controller = new AbortController();
oget.onclick = function() {
axios.get('http://localhost:3000/news',{
signal: controller.signal
})
.then(res => {
console.log(res.data);
}).catch(err => {
console.log("err",err);
})
}
oabort.onclick = function() {
controller.abort()
}
</script>
</body>
</html>
5 同源策略
- 一个URL有三部分组成:协议、域名(指向主机)、端口,只有这三个完全相同的 URL 才能称之为同源。
- 如下,能和
http://www.example.com/dir1/index.html
同源的是?
- 无法读取非同源网页的 Cookie、LocalStorage 。
- 无法接触非同源网页的 DOM。
- 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)。
- 注意:同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
6 解决跨域
6.1 jsonp
- Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
- 为什么我们从不同的域(网站)访问数据需要一个特殊的技术( JSONP )呢?这是因为同源策略。
- 1.txt代码:
txt
test("xiaowang")
- 01.html代码:
html
<!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>Document</title>
</head>
<body>
<script>
function test(data){
console.log("111",data);
}
var oscript = document.createElement("script")
oscript.src = "1.txt"
document.body.appendChild(oscript)
// 1.script标签没有跨域限制
// 2.后端配合返回的是 函数() 调用的方式
// 3.前端必须提前声明好这个函数
// 缺点:jsonp只能get请求 无法post、put、delete
</script>
<!-- <script>
// <script src="1.txt">
// test("xiaowang")
</script> -->
</body>
</html>
- 案例:
html
<!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>Document</title>
</head>
<body>
<input type="text" id="search">
<ul id="list">
</ul>
<script>
var osearch = document.querySelector('#search')
var olist = document.querySelector('#list')
osearch.oninput = function(){
// console.log(osearch.value)
if(osearch.value === "") {
olist.innerHTML = ""
return
}
var oscript = document.createElement("script")
oscript.src = `https://www.baidu.com/sugrec?pre=1&p=3&ie=utf-8&json=1&prod=pc&from=pc_web&sugsid=39646,39671,39663,39676,39678,39713,39791,39787,39704,39793,39681,39662&wd=${osearch.value}&req=2&csor=1&cb=test&_=1700639132336`
document.body.appendChild(oscript)
oscript.onload = function() {
oscript.remove() // 创建完script标签 等它load完了 就给它移掉
}
}
function test(data) {
// console.log(data.g);
olist.innerHTML = data.g.map(item =>
`
<li>${item.q}</li>
`
).join("")
}
</script>
</body>
</html>
6.2 其他技术手段
- 加上响应头
- 反向代理nginx跨域解决方案