作者:Cucci419_631 | 来源:互联网 | 2023-09-07 12:36
ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本json核心就是:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加
然后php方就会执行backfunc(传递参数);
所以流程就会分二步:
1:针对jsonp的预处理,主要是转化拼接这些参数,然后处理缓存,因为jsonp的方式也是靠加载script所以要关闭浏览器缓存
inspectPrefiltersOrTransports中,当作了jsonp的预处理后,还要在执行inspect(dataTypeOrTransport);的递归,就是为了关闭这个缓存机制
var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR);
/**
* 针对jonsp处理
*/
if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) {
//增加cache设置标记
//不需要缓存
//dataTypes: Array[2]
// 0: "script"
// 1: "json"
options.dataTypes.unshift(dataTypeOrTransport);
inspect(dataTypeOrTransport);
return false;
} else if (seekingTransport) {
return !(selected = dataTypeOrTransport);
}
具体的预处理的代码
// Detect, normalize options and install callbacks for jsonp requests
// 向前置过滤器对象中添加特定类型的过滤器
// 添加的过滤器将格式化参数,并且为jsonp请求增加callbacks
jQuery.ajaxPrefilter("json jsonp", function(s, originalSettings, jqXHR) {
var callbackName,
overwritten,
responseContainer,
// 如果是表单提交,则需要检查数据
jsOnProp= s.jsonp !== false && (rjsonp.test(s.url) ?
"url" :
typeof s.data === "string"
&& !(s.contentType || "").indexOf("application/x-www-form-urlencoded")
&& rjsonp.test(s.data) && "data"
);
// Handle iff the expected data type is "jsonp" or we have a parameter to set
// 这个方法只处理jsonp,如果json的url或data有jsonp的特征,会被当成jsonp处理
if (jsonProp || s.dataTypes[0] === "jsonp") {
// Get callback name, remembering preexisting value associated with it
// s.jsonpCallback时函数,则执行函数用返回值做为回调函数名
callbackName = s.jsOnpCallback= jQuery.isFunction(s.jsonpCallback) ?
s.jsonpCallback() :
s.jsonpCallback;
// Insert callback into url or form data
// 插入回调url或表单数据
// "test.php?symbol=IBM&callback=jQuery20309245402452070266_1402451299022"
if (jsonProp) {
s[jsonProp] = s[jsonProp].replace(rjsonp, "$1" + callbackName);
} else if (s.jsonp !== false) {
s.url += (ajax_rquery.test(s.url) ? "&" : "?") + s.jsonp + "=" + callbackName;
}
// Use data converter to retrieve json after script execution
s.converters["script json"] = function() {
if (!responseContainer) {
jQuery.error(callbackName + " was not called");
}
return responseContainer[0];
};
// force json dataType
// 强制跟换类型
s.dataTypes[0] = "json";
// Install callback
// 增加一个全局的临时函数
overwritten = window[callbackName];
window[callbackName] = function() {
responseContainer = arguments;
};
// Clean-up function (fires after converters)
// 在代码执行完毕后清理这个全部函数
jqXHR.always(function() {
// Restore preexisting value
window[callbackName] = overwritten;
// Save back as free
if (s[callbackName]) {
// make sure that re-using the options doesn't screw things around
s.jsOnpCallback= originalSettings.jsonpCallback;
// save the callback name for future use
oldCallbacks.push(callbackName);
}
// Call if it was a function and we have a response
if (responseContainer && jQuery.isFunction(overwritten)) {
overwritten(responseContainer[0]);
}
responseContainer = overwritten = undefined;
});
// Delegate to script
return "script";
}
});
jquery会在window对象中加载一个全局的函数,当代码插入时函数执行,执行完毕后就会被移除。同时jquery还对非跨域的请求进行了优化,如果这个请求是在同一个域名下那么他就会像正常的Ajax请求一样工作。
分发器执行代码:
当我们所有的参数都转化好了,此时会经过请求发送器用来处理发送的具体
为什么会叫做分发器,因为发送的请求目标
ajax因为参杂了jsonp的处理,所以实际上的请求不是通过 xhr.send(XmlHttpRequest)发送的
而是通过get方式的脚本加载的
所以
transports对象在初始化构件的时候,会生成2个处理器
- *: Array[1] 针对xhr方式
- script: Array[1] 针对script,jsonp方式
所以
transport = inspectPrefiltersOrTransports(transports, s, options, jqXHR);
那么得到的transport就会根据当前的处理的类型,来选择采用哪种发送器(*、script)
针对script的请求器
jQuery.ajaxTransport("script", function(s) {
// This transport only deals with cross domain requests
if (s.crossDomain) {
var script, callback;
return {
send: function(_, complete) {
script = jQuery("").prop({
async: true,
charset: s.scriptCharset,
//"http://192.168.1.114/yii/demos/test.php?backfunc=jQuery20308569577629677951_1402642881663&action=aaron&_=1402642881664"
src: s.url
}).on(
"load error",
callback = function(evt) {
script.remove();
callback = null;
if (evt) {
complete(evt.type === "error" ? 404 : 200, evt.type);
}
}
);
document.head.appendChild(script[0]);
},
abort: function() {
if (callback) {
callback();
}
}
};
}
});
此时就很明了吧
所以最终的实现就是通过动态加载脚本!