有时候我们需要3000端口的请求4000端口的数据,但是我们发送ajax请求时候,浏览器提示我们跨域了了。这个涉及到了浏览器的同源策略的安全问题。
-
浏览器同源策略
- 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源
- 源 :协议、域名和端口号
- 所以3000端口的请求4000端口的数据 即使,协议、域名一致了,端口号不一致。他就违背了同源策略,不能请求
-
跨域
-
不受同源策略影响的资源的引入的标签
,,,
Jsonp跨域请求
Jsonp 的出现就是利用script标签不受同源策略的特性而出现的。利用script标签的引用可能会出现变量污染,异步的问题。我们的Jsonp 封装就是要解决这样的问题。
-
动态创建script
通过返回回调函数解决异步和变量污染问题。
前端query 传递回调,后端返回带参数的函数
//前端 //cb function cbfn(res){ console.log(res); } btn.onclick = function(){ let o = document.createElement("script"); //***把函数传过去,不执行*** o.src = "http://localhost:4000/getAjax?cb=cbfn"; document.querySelector("head").appendChild(o); } //后端 router.get("/getAjax",(ctx,next)=>{ console.log("4000 run "); let cb = ctx.query.cb; // ctx.body = "var a = 20"; let obj = { a:20, b:20 } //***这里也不执行,当完成请求后,把数据返回客户端的那个时刻执行*** ctx.body = `${cb}(${JSON.stringify(obj)})`; })
ajax + jsonp 封装
ajax是同源的请求,我们可以把ajax和jsonp结合,利用一些传入配置,可以实现同源和跨域的请求
-
ajax + jsonp
接口配置dataType:"jsonp", 可以是ajax 那就没有问题是同源的,如果是jsonp 那么就执行动态创建script的逻辑函数。
jsonpFn(opts.url,opts.data,opts.jsonp,opts.success);给处理jsonp传递的参数(参考),url,data,jsonp(和后端约定俗称的名字),opts.success(回调函数)
jsonpFn函数的功能:
-
动态创建script
-
根据参数拼接url
我们目标是这样的url
http://localhost:4000/getAjax?name=张三&age=20&callback=cbfn
- name=张三&age=20 这个拼接可以使用函数改造一下,把对象遍历再用
&join一下 - 重点是函数名字和函数体。函数名字也好说和后端约定俗成了就是callback,但是opts.success 这里传入的是一个函数体,而我们只需要一个代表这个函数体的一个函数名。反正最后都会从后端传过来执行的。所以名字不重名就可以,名字可以使用Math.random() 随机创建
- name=张三&age=20 这个拼接可以使用函数改造一下,把对象遍历再用
let btn = document.querySelector("button"); btn.onclick = function(){ ajax({ url:"http://localhost:4000/getAjax", data:{ name:"张三", age:20 }, dataType:"jsonp", jsonp:"callback", success:function(res){ console.log(res) } }) } function ajax(options) { let opts = Object.assign({ method: 'get', url: '', headers: { 'content-type': 'application/x-www-form-urlencoded' }, jsonp:"cb", data: '', success: function () { } }, options) //处理jsonp请求; if(opts.dataType==="jsonp"){ jsonpFn(opts.url,opts.data,opts.jsonp,opts.success); return false; } function jsonpFn(url,data,cbName,cbFn){ // cbName cb/callback //随机的名字 let fnName = "ellen_"+Math.random().toString().substr(2); window[fnName] = cbFn; let path = url+"?"+o2u(data)+"&"+cbName+"="+fnName; // console.log(path); let o = document.createElement("script"); o.src = path; document.querySelector("head").appendChild(o); } ....ajax 请求的函数 .... //后端 router.get("/getAjax",(ctx,next)=>{ console.log("4000 run "); //约定的callback let cb = ctx.query.callback; let obj = { a:20, b:20 } //向前端传递的回调。== success ctx.body = `${cb}(${JSON.stringify(obj)})`; }) -
-
利用jsonp + ajax 请求百度接口
<script src="jsonp.js"></script> <title>Document</title> </head> <body> <h1>百度搜索</h1> <input type="text" class="myinput" /> <div class="exchange"></div> </body> <script> // console.log(ajax); document.querySelector(".myinput").onblur = function(){ ajax({ url:"https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su", dataType:"jsonp", data:{ wd:this.value }, success:function(res){ let data = res.s; let html = "<ul>"; data.forEach(v=>{ html += "<li>"+v+"</li>"; }) html += "</ul>"; document.querySelector(".exchange").innerHTML = html; } }) }