mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-65794 core: allow ajax calls to specify a cache key
This allows for better caching capabilities on servers. If a cache key is passed and the web service call does not require the user to be logged in we will attempt to use GET for the request. This allows for things like proxy caching on URLs. The cache key must be changed if we do not want to retrieve what has been cached and want to perform the request again.
This commit is contained in:
parent
7fa4e41052
commit
6a1ad7c677
@ -28,4 +28,6 @@
|
||||
*/
|
||||
|
||||
define('NO_MOODLE_COOKIES', true);
|
||||
define('ALLOW_GET_PARAMETERS', true);
|
||||
|
||||
require_once('service.php');
|
||||
|
@ -38,9 +38,24 @@ require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
define('PREFERRED_RENDERER_TARGET', RENDERER_TARGET_GENERAL);
|
||||
|
||||
$rawjson = file_get_contents('php://input');
|
||||
$arguments = '';
|
||||
$cacherequest = false;
|
||||
if (defined('ALLOW_GET_PARAMETERS')) {
|
||||
$arguments = optional_param('args', '', PARAM_RAW);
|
||||
$cachekey = optional_param('cachekey', '', PARAM_INT);
|
||||
if ($cachekey && $cachekey > 0 && $cachekey <= time()) {
|
||||
$cacherequest = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Either we are not allowing GET parameters or we didn't use GET because
|
||||
// we did not pass a cache key or the URL was too long.
|
||||
if (empty($arguments)) {
|
||||
$arguments = file_get_contents('php://input');
|
||||
}
|
||||
|
||||
$requests = json_decode($arguments, true);
|
||||
|
||||
$requests = json_decode($rawjson, true);
|
||||
if ($requests === null) {
|
||||
$lasterror = json_last_error_msg();
|
||||
throw new coding_exception('Invalid json in request: ' . $lasterror);
|
||||
@ -54,6 +69,7 @@ $settings->set_fileurl(true);
|
||||
$settings->set_filter(true);
|
||||
$settings->set_raw(false);
|
||||
|
||||
$haserror = false;
|
||||
foreach ($requests as $request) {
|
||||
$response = array();
|
||||
$methodname = clean_param($request['methodname'], PARAM_ALPHANUMEXT);
|
||||
@ -64,7 +80,19 @@ foreach ($requests as $request) {
|
||||
$responses[$index] = $response;
|
||||
if ($response['error']) {
|
||||
// Do not process the remaining requests.
|
||||
$haserror = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($cacherequest && !$haserror) {
|
||||
// 90 days only - based on Moodle point release cadence being every 3 months.
|
||||
$lifetime = 60 * 60 * 24 * 90;
|
||||
|
||||
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
|
||||
header('Pragma: ');
|
||||
header('Cache-Control: public, max-age=' . $lifetime . ', immutable');
|
||||
header('Accept-Ranges: none');
|
||||
}
|
||||
|
||||
echo json_encode($responses);
|
||||
|
2
lib/amd/build/ajax.min.js
vendored
2
lib/amd/build/ajax.min.js
vendored
@ -1 +1 @@
|
||||
define(["jquery","core/config","core/log","core/url"],function(a,b,c,d){var e=!1,f=function(a){var b,c,e,f=this,g=null,h=0;if(a.error)for(;h<f.length;h++)b=f[h],b.deferred.reject(a);else{for(h=0;h<f.length;h++){if(b=f[h],c=a[h],"undefined"==typeof c){g=new Error("missing response");break}if(c.error!==!1){g=c.exception,e=f[h].nosessionupdate;break}b.deferred.resolve(c.data)}null!==g&&("servicerequireslogin"!==g.errorcode||e?f.forEach(function(a){a.deferred.reject(g)}):window.location=d.relativeUrl("/login/index.php"))}},g=function(a,b,d){var f=this,g=0;for(g=0;g<f.length;g++){var h=f[g];e?(c.error("Page unloaded."),c.error(d)):h.deferred.reject(d)}};return{call:function(c,d,h,i,j){a(window).bind("beforeunload",function(){e=!0});var k,l=[],m=[],n=[],o="";for("undefined"==typeof h&&(h=!0),"undefined"==typeof d&&(d=!0),"undefined"==typeof j&&(j=0),"undefined"==typeof i&&(i=!1),k=0;k<c.length;k++){var p=c[k];l.push({index:k,methodname:p.methodname,args:p.args}),p.nosessionupdate=i,p.deferred=a.Deferred(),m.push(p.deferred.promise()),"undefined"!=typeof p.done&&p.deferred.done(p.done),"undefined"!=typeof p.fail&&p.deferred.fail(p.fail),p.index=k,n.push(p.methodname)}o=n.length<=5?n.sort().join():n.length+"-method-calls",l=JSON.stringify(l);var q={type:"POST",data:l,context:c,dataType:"json",processData:!1,async:d,contentType:"application/json",timeout:j},r="service.php",s=b.wwwroot+"/lib/ajax/";return h?s+=r+"?sesskey="+b.sesskey+"&info="+o:(r="service-nologin.php",s+=r+"?info="+o),i&&(s+="&nosessionupdate=true"),d?a.ajax(s,q).done(f).fail(g):(q.success=f,q.error=g,a.ajax(s,q)),m}}});
|
||||
define(["jquery","core/config","core/log","core/url"],function(a,b,c,d){var e=!1,f=function(a){var b,c,e,f=this,g=null,h=0;if(a.error)for(;h<f.length;h++)b=f[h],b.deferred.reject(a);else{for(h=0;h<f.length;h++){if(b=f[h],c=a[h],"undefined"==typeof c){g=new Error("missing response");break}if(c.error!==!1){g=c.exception,e=f[h].nosessionupdate;break}b.deferred.resolve(c.data)}null!==g&&("servicerequireslogin"!==g.errorcode||e?f.forEach(function(a){a.deferred.reject(g)}):window.location=d.relativeUrl("/login/index.php"))}},g=function(a,b,d){var f=this,g=0;for(g=0;g<f.length;g++){var h=f[g];e?(c.error("Page unloaded."),c.error(d)):h.deferred.reject(d)}};return{call:function(c,d,h,i,j,k){a(window).bind("beforeunload",function(){e=!0});var l,m=[],n=[],o=[],p="",q=2e3;for("undefined"==typeof h&&(h=!0),"undefined"==typeof d&&(d=!0),"undefined"==typeof j&&(j=0),"undefined"==typeof k?k=null:(k=parseInt(k),k<=0?k=null:k||(k=null)),"undefined"==typeof i&&(i=!1),l=0;l<c.length;l++){var r=c[l];m.push({index:l,methodname:r.methodname,args:r.args}),r.nosessionupdate=i,r.deferred=a.Deferred(),n.push(r.deferred.promise()),"undefined"!=typeof r.done&&r.deferred.done(r.done),"undefined"!=typeof r.fail&&r.deferred.fail(r.fail),r.index=l,o.push(r.methodname)}p=o.length<=5?o.sort().join():o.length+"-method-calls",m=JSON.stringify(m);var s={type:"POST",context:c,dataType:"json",processData:!1,async:d,contentType:"application/json",timeout:j},t="service.php",u=b.wwwroot+"/lib/ajax/";if(h?u+=t+"?sesskey="+b.sesskey+"&info="+p:(t="service-nologin.php",u+=t+"?info="+p,k&&(u+="&cachekey="+k,s.type="GET")),i&&(u+="&nosessionupdate=true"),"POST"===s.type)s.data=m;else{var v=u+"&args="+encodeURIComponent(m);v.length>q?(s.type="POST",s.data=m):u=v}return d?a.ajax(u,s).done(f).fail(g):(s.success=f,s.error=g,a.ajax(u,s)),n}}});
|
@ -137,9 +137,13 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
* @param {Boolean} nosessionupdate Optional, defaults to false.
|
||||
* If true, the timemodified for the session will not be updated.
|
||||
* @param {Integer} timeout number of milliseconds to wait for a response. Defaults to no limit.
|
||||
* @param {Integer} cachekey This is used in order to identify the request. If this id changes then we
|
||||
* will be sending a different URL and any caching (eg. browser, proxy) knows that it
|
||||
* should perform another request and not use the cache. Note - this variable is only
|
||||
* used when we are calling 'service-nologin.php'. See MDL-65794.
|
||||
* @return {Promise[]} Array of promises that will be resolved when the ajax call returns.
|
||||
*/
|
||||
call: function(requests, async, loginrequired, nosessionupdate, timeout) {
|
||||
call: function(requests, async, loginrequired, nosessionupdate, timeout, cachekey) {
|
||||
$(window).bind('beforeunload', function() {
|
||||
unloading = true;
|
||||
});
|
||||
@ -149,6 +153,8 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
methodInfo = [],
|
||||
requestInfo = '';
|
||||
|
||||
var maxUrlLength = 2000;
|
||||
|
||||
if (typeof loginrequired === "undefined") {
|
||||
loginrequired = true;
|
||||
}
|
||||
@ -158,6 +164,16 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
if (typeof timeout === 'undefined') {
|
||||
timeout = 0;
|
||||
}
|
||||
if (typeof cachekey === 'undefined') {
|
||||
cachekey = null;
|
||||
} else {
|
||||
cachekey = parseInt(cachekey);
|
||||
if (cachekey <= 0) {
|
||||
cachekey = null;
|
||||
} else if (!cachekey) {
|
||||
cachekey = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof nosessionupdate === "undefined") {
|
||||
nosessionupdate = false;
|
||||
@ -193,7 +209,6 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
ajaxRequestData = JSON.stringify(ajaxRequestData);
|
||||
var settings = {
|
||||
type: 'POST',
|
||||
data: ajaxRequestData,
|
||||
context: requests,
|
||||
dataType: 'json',
|
||||
processData: false,
|
||||
@ -207,6 +222,10 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
if (!loginrequired) {
|
||||
script = 'service-nologin.php';
|
||||
url += script + '?info=' + requestInfo;
|
||||
if (cachekey) {
|
||||
url += '&cachekey=' + cachekey;
|
||||
settings.type = 'GET';
|
||||
}
|
||||
} else {
|
||||
url += script + '?sesskey=' + config.sesskey + '&info=' + requestInfo;
|
||||
}
|
||||
@ -215,6 +234,19 @@ define(['jquery', 'core/config', 'core/log', 'core/url'], function($, config, Lo
|
||||
url += '&nosessionupdate=true';
|
||||
}
|
||||
|
||||
if (settings.type === 'POST') {
|
||||
settings.data = ajaxRequestData;
|
||||
} else {
|
||||
var urlUseGet = url + '&args=' + encodeURIComponent(ajaxRequestData);
|
||||
|
||||
if (urlUseGet.length > maxUrlLength) {
|
||||
settings.type = 'POST';
|
||||
settings.data = ajaxRequestData;
|
||||
} else {
|
||||
url = urlUseGet;
|
||||
}
|
||||
}
|
||||
|
||||
// Jquery deprecated done and fail with async=false so we need to do this 2 ways.
|
||||
if (async) {
|
||||
$.ajax(url, settings)
|
||||
|
@ -3,6 +3,13 @@ information provided here is intended especially for developers.
|
||||
|
||||
This information is intended for authors of webservices, not people writing webservice clients.
|
||||
|
||||
=== 3.8 ===
|
||||
|
||||
* Ajax calls can now specify a cache key. This allows for better caching capabilities on servers. If a cache key
|
||||
is passed and the web service call does not require the user to be logged in we will attempt to use GET for the
|
||||
request. This allows for things like proxy caching on URLs. The cache key must be changed if we do not want to
|
||||
retrieve what has been cached and want to perform the request again.
|
||||
|
||||
=== 3.7 ===
|
||||
|
||||
* External function core_webservice_external::get_site_info() now returns the current site theme (for the user).
|
||||
|
Loading…
x
Reference in New Issue
Block a user