同源策略: 同一个端口,一个域名,一个协议才能访问服务器;
Part One : jsonp
原理: 通过script标签的src属性加载js不受同源策略控制:
首先定义一个处理数据的方法:
const handleRequest = function (json) {
console.log(json);
}
注意此处的handleRequest是全局函数,如果window会被污染,建议直接添加事件格式为 window.handleRequest = ...
创建script标签:
let _script = document.createElement("script");
添加属性上去,然后传一个回调函数过去:
// 此处的handleRequest为全局定义的方法,用来执行接收收据后的callback
_script.setAttribute("src",url+"?callback=handleRequest");
将script标签添加到head标签上,为什么要添加到head标签呢?怕影响到其他dom元素
document.head.appendChild(_script);
将上面的操作封装到一个方法:
// 处理返回的请求
const handleRequest = function (json) {
console.log(json);
}
function CrossDomain(url){
let _script = document.createElement("script");
_script.setAttribute("src",url+"?callback=handleRequest");
document.head.appendChild(_script);
}
CrossDomain("http://localhost:8080/script");
好了,客户端逻辑写好了,服务端如何配置呢?
其实原理很简单,首先获取函数名,然后request.body上传入要执行的函数的字符串形式:
此处使用koa框架进行简单演示:
const forScript = async function(ctx,next){
let {callBack} = ctx.request.query;
ctx.response.body = `${callBack}(333)`;
}
app.use(route.get("/script",forScript));
就可以成功了!
Part Two: CROS跨域资源请求
首先,客户端请求分为两种:
(一) 简单请求:
(1) 请求方法是以下三种方法之一:
- HEAD
- GET
- POST
(2)HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
此时服务器应该设置:
ctx.response.set("Access-Control-Allow-Origin","*");
如果需要接收cookie,则需要设置:
ctx.response.set("Access-Control-Allow-Credentials","true");
注意,此时Access-Control-Allow-Orign就不能设置为星号了,需要设置为具体的ip;
(二)非简单请求:
超出上面规定的请求,发送非简单请求时,浏览器会先向服务器发起预请求,方法为OPTIONS,如果确认能接受此方法后,再发起正式请求;
此时,再进行普通的请求转发;
如put请求,需要在koa中的路由定义options方法的处理:
app.use(route.options("/cros",async (ctx,next)=>{
console.log("处理options");
ctx.response.set("Access-Control-Allow-Origin","null");
ctx.response.set("Access-Control-Allow-Credentials","true");
ctx.response.set('Access-Control-Allow-Headers', 'Content-type');
// 意思等同于请求执行成功,但是没有数据
ctx.response.status = 204;
ctx.response.set("Access-Control-Allow-Methods","POST,GET,PUT");
}));
然后定义put请求的处理:
app.use(route.put("/cros",async (ctx,next)=>{
console.log("处理put");
ctx.response.set("Access-Control-Allow-Origin","null");
ctx.response.set("Access-Control-Allow-Credentials","true");
ctx.response.body = "处理put";
}))
接着就能成功返回了!
Part Three nginx反向代理
此方法需要安装nginx服务器,让nginx将请求转发到目标要求的地址:
具体配置如下,首先进入到nginx.conf
cd /etc/nginx
# vi编辑脚本
sudo vi nginx.conf
修改其中的server为:
http {
server {
# 设置默认索引
index g.html;
# 设置项目所在根目录
root /home/yangdilin/koa/;
# 监听80端口
listen 80;
# nginx服务器的IP地址或域名
server_name localhost;
# 代理的端口
location /api/cros {
# 请求转发的地址
proxy_pass http://127.0.0.1:8080/cros;
}
}
sudo nginx -s -reload
既可以代理成功!nginx还可以直接设置响应头Acess-Control-Allow-Origin,实现方法二的CORS,具体就不进行介绍了;