06跨域
第一章: 跨域
1、 同源策略
同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。
同源(同一个来源):协议、域名、端口号 必须完全相同 ==> 比如http://127.0.0.1:3000
,后面的/server、/data
等可以不同
违背同源策略就是跨域 ==> 比如http协议向https协议发送请求,a.com 向 b.com 发送请求,300端口向8000端口发送请求
AJAX默认遵循的是同源策略
<body>
<h1>尚硅谷</h1>
<button>点击获取用户数据</button>
<script>
const btn = document.querySelector('button');
btn.onclick = function(){
const x = new XMLHttpRequest();
//这里因为是满足同源策略的, 所以 url 可以简写
x.open("GET",'/data');
//发送
x.send();
//
x.onreadystatechange = function(){
if(x.readyState === 4){
if(x.status >= 200 && x.status < 300){
console.log(x.response);
}
}
}
}
</script>
</body>
const express = require('express');
const app = express();
app.get('/home', (request, response)=>{
//响应一个页面
// dirname 前面是两个下划线
response.sendFile(__dirname + '/index.html');
});
app.get('/data', (request, response)=>{
response.send('用户数据');
});
app.listen(9000, ()=>{
console.log("服务已经启动...");
});
2、 如何解决跨域
2.1 JSONP
-
JSONP是什么
JSONP (JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持get请求
-
JSONP 怎么工作的?
在网页有一些标签天生具有跨域能力,比如:img, link, iframe, script
JSONP就是利用script标签的跨域能力来发送请求的
-
JSONP的使用
- 动态的创建一个script标签
var script = document.createElement("script");
- 设置script的src,设置回调函数
script.src = "http://locallhost:3000/textAJAX?callback=abc"
2.2 JSONP原理
我们本地写的以后缀为.html
结尾的链接是以file
协议的
script
文件生成的链接是http
协议的,因此script标签本身支持跨域能力
我们可以借助open with live server
找到js文件
,以http协议
的链接
<body>
<div class="root"></div>
<script>
function handleData(data) {
let root = document.querySelector('.root')
// console.log(root);
root.innerText = data.msg
}
</script>
<script src="http://127.0.0.1:5500/04%E5%90%8C%E6%BA%90/app.js"></script>
</body>
app.js
const data = {
name: '尚硅谷atguigu'
};
handle(data);
当参数为String,该方法将设置Content-Type为
“text / html”:
res.send('<p>some html</p>');
当参数是Array或Object,Express以JSON表示响应:
res.send({ user: 'tobi' });
res.send([1,2,3])
- 参数类型的区别:
- res.end() 参数为: a Buffer object / a String
- res.send() 参数为: a Buffer object / a String / an object / an Array
2.发送服务器内容不同
- res.end() 只接受服务器响应数据,如果是中文则会乱码
- res.send() 发送给服务端时,会自动发送更多的响应报文头,其中包括 Content-Tpye: text/html; charset=uft-8,所以中文不会乱码
<body>
<div id="result"></div>
<script>
//处理数据
function handle(data) {
//获取 result 元素
const result = document.getElementById('result');
result.innerHTML = data.name;
}
</script>
<!-- <script src="http://127.0.0.1:5500/%E8%AF%BE%E5%A0%82/%E4%BB%A3%E7%A0%81/7-%E8%B7%A8%E5%9F%9F/2-JSONP/js/app.js"></script> -->
<script src="http://127.0.0.1:8000/jsonp-server"></script>
</body>
需要注意的是,不需要再去将str转为对象,如果下面直接使用对象传过去,会自动帮我们调用toString方法
??那不用在去处理将它转为对象吗??
//jsonp服务
app.all('/jsonp-server',(request, response) => {
// response.send('console.log("hello jsonp")');
const data = {
name: '尚硅谷atguigu'
};
//将数据转化为字符串
let str = JSON.stringify(data);
//返回结果
//end不会加响应头
// 使用了es6的插值语法
response.end(`handle(${str})`);
});
注意:end函数中的符号为斜点,不是单引号
可以理解,返回的为js语句。同步给了script标签,在这个过程,它执行了脚本,调用了handle函数。
个人理解:${}是将函数代码先转换成js引擎可以识别的字符串,然后js引擎将其再转化为javascript语言规范的代码
2.3 jsonp实战
需求:当输入用户名以后,在失去焦点的时候向服务器发送请求,检测用户名是否已经存在
<body>
用户名: <input type="text" id="username">
<p></p>
<script>
//获取 input 元素
const input = document.querySelector('input');
const p = document.querySelector('p');
//声明 handle 函数
function handle(data){
input.style.border = "solid 1px #f00";
//修改 p 标签的提示文本
p.innerHTML = data.msg;
}
//绑定事件
input.onblur = function(){
//获取用户的输入值
let username = this.value;
//向服务器端发送请求 检测用户名是否存在
//1. 创建 script 标签
const script = document.createElement('script');
//2. 设置标签的 src 属性
script.src = 'http://127.0.0.1:8000/check-username';
//3. 将 script 插入到文档中
document.body.appendChild(script);
}
</script>
</body>
//用户名检测是否存在
// 这里支持get和all
app.all('/check-username',(request, response) => {
// response.send('console.log("hello jsonp")');
const data = {
exist: 1,
msg: '用户名已经存在'
};
//将数据转化为字符串
let str = JSON.stringify(data);
//返回结果
response.end(`handle(${str})`);
});
3、 CORS
推荐阅读:
- http://www.ruanyifeng.com/blog/2016/04/cors.html
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
-
CORS是什么?
CORS (Cross-Origin Resource Sharing), 跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 等请求。跨域资源共享标准新增了一组 HTTP 首部字段(响应头),允许服务器声明哪些源站通过浏览器有权限访问哪些资源
-
CORS怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
-
CORS 的使用
主要是服务端的设置:
rounter.get("/testAJAX",function(req, res){ // 允许所有端口网页访问 response.setHeader("Access-Control-Allow-Origin", "*"); // response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500"); })
平时的open with liver serve插件 就是默认开启了一个5500端口的服务器
-
还可以设置其他的响应头,以及其它信息等
参见mdn文档 cros
app.all('/cors-server', (request, response)=>{ //设置响应头 response.setHeader("Access-Control-Allow-Origin", "*"); // 允许自定义头信息数据 response.setHeader("Access-Control-Allow-Headers", '*'); // 允许自定义请求方法 response.setHeader("Access-Control-Allow-Method", '*'); // response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500"); response.send('hello CORS'); });