同源策略和跨域请求的实现
一、什么是同源策略
如果两个 URL 的 protocol、port (en-US) (如果有指定的话) 和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是“元组”。(“元组”是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。
| centered 文本居中 | right-aligned 文本居右 |
URL | 结果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html | 同源 | 只有路径不同 |
http://store.company.com/dir/inner/another.html | 同源 | 只有路径不同 |
https://store.company.com/secure.html | 失败 | 协议不同 |
http://store.company.com:81/dir/etc.html | 失败 | 端口不同 ( http:// 默认端口是 80) |
http://news.company.com/dir/other.html | 失败 | 主机不同 |
说大白话就是防止不是来自同一个源头的js脚本互相通信,这个源头可以是服务器
如果两个js是来自同一个服务器端口是可以传数据的
二、同源数据传输例子
服务端
let express=require("express")
const app=express()
app.get("/index",(require,response)=>{
response.sendFile(__dirname+"/indexa.html")//__dirname是绝对路径
})//浏览器请求默认是get,设置post请求浏览器输入网址无效
app.get("/data",(require,response)=>{
response.send("用户的数据")
})
app.all("/jsonp",(require,response)=>{
const data={
exist:1,
msg:"用户名以及存在"
}
let str=JSON.stringify(data)
response.end(`handle(${str})`)
})
app.listen(3101,()=>{
console.log("启动成功了")
})
客户端:
<!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">
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<title>Document</title>
</head>
<body>
<label >
用户名<input type="text" >
<p></p>
</label>
<!-- <script src="./ajax_jsonp.js"></script>//script标签自带跨域效果,且默认为全局变量 -->
<script>
let input=document.querySelector("input")
let p=document.querySelector("p")
function handle(data){
input.style.border="10px #10b solid"
p.innerText=data.msg
}
input.onblur=function(){
let name=this.value
let onscript=document.createElement("script")
onscript.src="http://127.0.0.1:3101/jsonp"
document.body.appendChild(onscript)
}
</script>
</body>
</html>
注意事项:
以vscode为例:
是在服务器端请求页面后在请求数据,而不是以本地文件,或者插件的模式打开
因为文件的形式file:///D:/%E6%96%B0%E5%BE%81%E7%A8%8B/ajax/ajax_jsonp.html
live server的
http://127.0.0.1:5500/ajax_jsonp.html
服务端的url
http://127.0.0.1:5500/
上面的两个url都会跨域
先输入服务端地址加上路由 /index
服务端会发送html页面
然后这是的页面url是http://127.0.0.1:5500/
然后改页面向url是http://127.0.0.1:5500/的服务端请求数据,
这样一定是同源
很多时候页面和数据都是同一台服务器发送的,这样可以避免跨域问题
三、jsonp野路子(不推荐,了解一下就行)
可以参考下我之前的文章,点击查看下
四、 response.setHeader的设置
response.setHeader("Access-Control-Allow-Origin","*")
在服务端里加入这么一行代码跨域问题就简单解决了
这个是允许所有的url客户端可以访问,你可以换成相应的url
样例
客户端:
<!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>发送ajax请求</button>
<div id="result">
</div>
</body>
<script>
const btn=document.querySelector("button")
const div=document.getElementById("result")
btn.onclick=function(){
const x=new XMLHttpRequest()
x.open("GET","http://127.0.0.1:3101/cros")
x.send()
x.onreadystatechange=function(){
if(x.readyState==4){
if(x.status>=200&x.status<300){
console.log(x.response)
}
}
}
}
</script>
</html>
服务端:
let express=require("express")
const app=express()
app.all("/cros",(require,response)=>{
// response.setHeader("Access-Control-Allow-Origin","*")
response.setHeader("Access-Control-Allow-Origin","http://127.0.0.1:5500")
response.setHeader("Access-Control-Allow-Method","*")//允许的请求方法,如果get,post,这里是全部
response.setHeader("Access-Control-Allow-Headers","*")//允许自定义的头属性
response.end("cros")
})
app.listen(3101,()=>{
console.log("启动成功了")
})
运行截图:
五、温故而知新
response.setHeader的其他经常用的设置
response.setHeader(“Access-Control-Allow-Origin”,“http://127.0.0.1:5500”)//允许指定的url请求
response.setHeader(“Access-Control-Allow-Method”,““)//允许的请求方法,如果get,post,这里是全部
response.setHeader(“Access-Control-Allow-Headers”,””)
//允许自定义的头属性,原生的ajax不加,http的响应报文头不能有自定义键值对
axios不影响,因为可以自己写在headers里