axios自定义的jsonp适配器

回到文章>>

COPYHTML

<p>打开network面板可以看到这两个请求的发起方式是不一样的</p> <p>一个是通过请求js产生的,一个是XMLHttpRequest产生的</p>

COPYJAVASCRIPT

function isAbsoluteURL(url) { // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL). // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed // by any combination of letters, digits, plus, period, or hyphen. return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url); } /** * Creates a new URL by combining the specified URLs * * @param {string} baseURL The base URL * @param {string} relativeURL The relative URL * @returns {string} The combined URL */ function combineURLs(baseURL, relativeURL) { return relativeURL ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') : baseURL; } function buildFullPath(baseURL = '', requestedURL = '') { if (baseURL && !isAbsoluteURL(requestedURL)) { return combineURLs(baseURL, requestedURL); } return requestedURL; } function buildURL(url, params, paramsSerializer) { /*eslint no-param-reassign:0*/ if (!params) { return url; } var serializedParams; var parts = []; for (var key in params) { parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`); } serializedParams = parts.join('&'); if (serializedParams) { var hashmarkIndex = url.indexOf('#'); if (hashmarkIndex !== -1) { url = url.slice(0, hashmarkIndex); } url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams; } return url; } // 这里的config是axios里所有的配置 var jsonpAdapter = (config) => { return new Promise((resolve, reject) => { // 是否已取消当前操作 // 因jsonp没有主动取消请求的方式 // 这里使用 isAbort 来标识 var isAbort = false; // 定时器标识符 var timer = null; // 执行方法的名字, var callbackName = `jsonp${Date.now()}_${Math.random().toString().slice(2)}`; // 这里假设已经实现了baseURL和url的拼接方法 var fullPath = buildFullPath(config.baseURL, config.url); // 这里假设已经实现了url和参数的拼接方法 // 不太一样的地方在于,jsonp需要额外插入一个自己的回调方法 var url = buildURL( fullPath, { ...config.params, ...{ [config.jsonpCallback || 'callback']: callbackName }, }, config.paramsSerializer ); // 创建一个script标签 var script = document.createElement('script'); // 成功执行操作后 function remove() { if (script) { script.onload = script.onerror = null; // 移除script标签 if (script.parentNode) { script.parentNode.removeChild(script); } // 取消定时器 if (timer) { clearTimeout(timer); } script = null; } } // 成功请求后 window[callbackName] = (data) => { // 若已需要请求,则不再执行 if (isAbort) { return; } // 返回的格式 var response = { status: 200, statusText: 'ok', config, request: script, data: data, }; remove(); // 实际上这里上一个settle操作,会额外判断是否是合理的status状态 // 若我们在config.validateStatus中设置404是合理的,也会进入到resolve状态 // 但我们这里就不实现这个了 // settle(resolve, reject, response); resolve(response); }; // 请求失败 script.onerror = function (error) { remove(); reject(createError('Network Error', config, 404)); }; // 若设置了超时时间 if (config.timeout) { timer = setTimeout(function () { remove(); // 取消当前操作 isAbort = true; reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 405)); }, config.timeout); } // 若定义了取消操作 if (config.cancelToken) { config.cancelToken.promise.then(function () { if (!script) { return; } remove(); isAbort = true; reject(createError('Cancel Error', config, 404)); }); } script.src = url; var target = document.getElementsByTagName('script')[0] || document.head; target.parentNode && target.parentNode.insertBefore(script, target); }); }; var request = axios.create({ adapter: function (config) { if (config.params && config.params.format === 'jsonp') { return jsonpAdapter(config); } // 这里需要将config.adapter设置为空 // 否则会造成无限循环 return axios(Object.assign({}, config, { adapter: undefined })); }, }); // 使用自定义的适配器jsonp发起请求 request('https://api.prize.qq.com/v1/newsapp/answer/share/oneQ?qID=506336', { params: { format: 'jsonp', }, }) .then(function (response) { console.log('jsonp response', response); }) .catch(function (error) { console.error('jsonp error', error); }); // 使用axios默认的适配器发起请求 request('https://api.prize.qq.com/v1/newsapp/answer/share/oneQ?qID=506336') .then(function (response) { console.log('axios response', response); }) .catch(function (error) { console.error('axios error', error); });
新窗口打开