JSONP的由来
1、Ajax直接请求普通文件存在跨域无权限访问的问题,不管是静态页面、动态页面、web服务,只要是跨域请求,一律不准。
2、不过我们发现,web页面调用js文件则不受跨域的影响(不仅如此,我们还发现凡是拥有“src”这个属性的标签都拥有跨域的能力,比如<\script>、<\img>、<\iframe>)。
3、于是可以判断,当前阶段如果想通过纯web端跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理。
4、恰巧我们知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据。
5、这样,解决方案就呼之欲出了,web服务端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件,显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装进去。
6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来很像ajax,但其实并不一样。
7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,简称JSONP。该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名包裹在JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
利用jquery实现jsonp
js代码
<script type="application/javascript">
$("#jsonp").on('click',function () {
$.ajax({
type: "GET",
url: "/jsonp/jsonpTest",
dataType: 'jsonp',
jsonp: "callback",
success: function (response, status, xhr) {
console.log(response,status,xhr);
},
error: function () {
console.log("请求失败");
}
});
});
</script>
java后端代码
import cn.hutool.json.JSONUtil;
import com.compass.account.plugin.RedisDelayQueue;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* @ignore
* @author HuYu
* @date 2023-06-10
* @since 1.0
**/
@Controller
@RequestMapping("/jsonp")
public class JSONPController {
@Resource
private RedisDelayQueue redisDelayQueue ;
/**
* jsonp测试
* @return java.lang.String
* @author compass
* @date 2023/6/10 1:57
* @since 1.0.0
**/
@ResponseBody
@GetMapping(value = "/jsonpTest" , produces = {"application/javascript"})
public String getUserInfo(@RequestParam("callback") String callback, HttpServletResponse response) {
response.setContentType("text/html;charset=utf-8");
Map<String,String> resultMap = new HashMap<>();
resultMap.put("msg","请求成功");
resultMap.put("code","200");
resultMap.put("data","admin");
String jsonStr = JSONUtil.toJsonStr(resultMap);
return callback+"(" + jsonStr + ")";
}
}
使用原生js调用jsonp
js代码:后端代码不变文章来源:https://www.toymoban.com/news/detail-598656.html
/**
* 使用原生js发送jsonp请求,当请求结束后返回一个Promise回调
* @description 使用方式:getRequest('/jsonp/jsonpTest').then(result=>{ console.log(result) })
* @param url
* @returns {Promise<Object>}
*/
function getRequest(url) {
return new Promise(((resolve) => {
// 创建一个全局函数回调
if (!window.jsonResultHandler){
window.jsonResultHandler = function (data) {
resolve(data);
};
}
url = url.indexOf('?')===-1?(url+'?callback=jsonResultHandler'):(url+'&callback=jsonResultHandler');
let callbackId = 'callback'+new Date().getTime();
let script = document.createElement('script');
script.setAttribute('src', url);
script.setAttribute('id', callbackId);
document.getElementsByTagName('head')[0].appendChild(script);
// script加载完成后执行回调,然后删除掉scrip标签
if(script.readyState){
script.onreadystatechange=function(){
if(script.readyState==='complete'||script.readyState==='loaded'){
script.onreadystatechange=null;
window.jsonResultHandler();
let callbackDom = document.getElementById(callbackId);
if (callbackDom){
callbackDom.remove();
}
}
}
}else{
script.onload=function(){
window.jsonResultHandler();
let callbackDom = document.getElementById(callbackId);
if (callbackDom){
callbackDom.remove();
}
}
}
}))
}
getRequest('/jsonp/jsonpTest').then(result=>{
console.log(result)
})
核心思路:就是利用script标签不会产生跨域,然后使用script标签去发送请求,然后后端返回一个script类型回调函数,然后这个回调函数在前端是一个全局变量的函数,随后被后端回调,这样就解决了跨域的问题,但是这种方式只支持get请求。文章来源地址https://www.toymoban.com/news/detail-598656.html
到了这里,关于jsonp解决跨域的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!