diff --git a/docs/zh-CN/types/api.md b/docs/zh-CN/types/api.md index 5f852e81f..de89f2ecf 100755 --- a/docs/zh-CN/types/api.md +++ b/docs/zh-CN/types/api.md @@ -871,6 +871,13 @@ Content-Disposition: attachment; filename="download.pdf" Access-Control-Expose-Headers: Content-Disposition ``` +如果自己覆盖了 `fetcher` 函数,需要有类似如下代码,具体可以参考 `embed.tsx` 里的实现 + +```javascript +let response = await axios(config); +response = await attachmentAdpator(response, __); +``` + ### 配置提示信息 可以通过`messages`自定义接口请求提示信息。 diff --git a/examples/components/SchemaRender.jsx b/examples/components/SchemaRender.jsx index 172960569..02affd385 100644 --- a/examples/components/SchemaRender.jsx +++ b/examples/components/SchemaRender.jsx @@ -5,7 +5,7 @@ import Portal from 'react-overlays/Portal'; import {normalizeLink} from 'amis-core'; import {withRouter} from 'react-router'; import copy from 'copy-to-clipboard'; -import {qsparse, parseQuery} from 'amis-core'; +import {qsparse, parseQuery, attachmentAdpator} from 'amis-core'; import isPlainObject from 'lodash/isPlainObject'; function loadEditor() { @@ -106,16 +106,29 @@ export default function (schema, schemaProps, showCode, envOverrides) { return false; }, - fetcher: ({url, method, data, config, headers}) => { + fetcher: async ({ + url, + method, + data, + responseType, + config, + headers + }) => { config = config || {}; - config.headers = headers || {}; + config.url = url; + responseType && (config.responseType = responseType); if (config.cancelExecutor) { config.cancelToken = new axios.CancelToken(config.cancelExecutor); } - if (data && data instanceof FormData) { - // config.headers = config.headers || {}; + config.headers = headers || {}; + config.method = method; + config.data = data; + + if (method === 'get' && data) { + config.params = data; + } else if (data && data instanceof FormData) { // config.headers['Content-Type'] = 'multipart/form-data'; } else if ( data && @@ -127,19 +140,40 @@ export default function (schema, schemaProps, showCode, envOverrides) { config.headers['Content-Type'] = 'application/json'; } - if (method !== 'post' && method !== 'put' && method !== 'patch') { - if (data) { - if (method === 'delete') { - config.data = data; - } else { - config.params = data; - } - } + // 支持返回各种报错信息 + config.validateStatus = function () { + return true; + }; - return axios[method](url, config); + let response = await axios(config); + response = await attachmentAdpator(response, s => { + return s; + }); + + if (response.status >= 400) { + if (response.data) { + // 主要用于 raw: 模式下,后端自己校验登录, + if ( + response.status === 401 && + response.data.location && + response.data.location.startsWith('http') + ) { + location.href = response.data.location.replace( + '{{redirect}}', + encodeURIComponent(location.href) + ); + return new Promise(() => {}); + } else if (response.data.msg) { + throw new Error(response.data.msg); + } else { + throw new Error(JSON.stringify(response.data, null, 2)); + } + } else { + throw new Error(`${response.status}`); + } } - return axios[method](url, data, config); + return response; }, isCancel: value => axios.isCancel(value), copy: (content, options) => { diff --git a/mock/cfc/index.js b/mock/cfc/index.js index 143e2d791..53c3d0c07 100755 --- a/mock/cfc/index.js +++ b/mock/cfc/index.js @@ -49,6 +49,18 @@ function mockResponse(event, context, callback) { json: false, body: res }); + }, + download(file) { + callback(null, { + statusCode: 200, + headers: { + ...createHeaders(event.headers), + 'Content-Type': 'application/octet-stream', + 'Content-Disposition': `attachment; filename="${file}"` + }, + json: false, + download: file + }); } }; } diff --git a/mock/cfc/mock/download.zip b/mock/cfc/mock/download.zip new file mode 100644 index 000000000..c572e2476 Binary files /dev/null and b/mock/cfc/mock/download.zip differ diff --git a/mock/cfc/mock/index.js b/mock/cfc/mock/index.js index 7a1a7783e..a73d865ce 100755 --- a/mock/cfc/mock/index.js +++ b/mock/cfc/mock/index.js @@ -2,58 +2,66 @@ const path = require('path'); const fs = require('fs'); const DIRNAME = path.dirname(__filename); -module.exports = function(req, res) { - const subpath = (req.originalUrl || req.url).replace(/^\/(api\/mock2|api)\/|\?.*$/g, ''); - const jsonFile = subpath + '.json'; - const jsFile = subpath + '.js'; +module.exports = function (req, res) { + const subpath = (req.originalUrl || req.url).replace( + /^\/(api\/mock2|api)\/|\?.*$/g, + '' + ); + const jsonFile = subpath + '.json'; + const jsFile = subpath + '.js'; - if (subpath == 'options/users') { - let json = readJson(jsonFile); - let term = req.query.term; + if (subpath == 'options/users') { + let json = readJson(jsonFile); + let term = req.query.term; - if (term) { - json.data = json.data.filter(item => item.label.substring(0, term.length) === term); - } - - return res.json(json); - } else if (/^sample/.test(subpath)) { - let file = require.resolve(path.join(DIRNAME, 'sample.js')); - delete require.cache[file]; - return require(file)(req, res); - } else if (exist(jsFile)) { - let file = require.resolve(path.join(DIRNAME, jsFile)); - delete require.cache[file]; - - if (req.query.waitSeconds) { - return setTimeout(function() { - require(file)(req, res); - }, parseInt(req.query.waitSeconds, 10) * 1000); - } - - return require(file)(req, res); - } if (exist(jsonFile)) { - if (req.query.waitSeconds) { - return setTimeout(function() { - res.json(readJson(jsonFile)); - }, parseInt(req.query.waitSeconds, 10) * 1000); - } - - return res.json(readJson(jsonFile)); - } else if (/crud\/\d+$/.test(subpath) && req.method === 'DELETE') { - return res.json({ - status: 0, - msg: '删除成功' - }) + if (term) { + json.data = json.data.filter( + item => item.label.substring(0, term.length) === term + ); } - res.json(readJson('notFound.json')); -} + return res.json(json); + } else if (/^sample/.test(subpath)) { + let file = require.resolve(path.join(DIRNAME, 'sample.js')); + delete require.cache[file]; + return require(file)(req, res); + } else if (exist(jsFile)) { + let file = require.resolve(path.join(DIRNAME, jsFile)); + delete require.cache[file]; + + if (req.query.waitSeconds) { + return setTimeout(function () { + require(file)(req, res); + }, parseInt(req.query.waitSeconds, 10) * 1000); + } + + return require(file)(req, res); + } + if (exist(jsonFile)) { + if (req.query.waitSeconds) { + return setTimeout(function () { + res.json(readJson(jsonFile)); + }, parseInt(req.query.waitSeconds, 10) * 1000); + } + + return res.json(readJson(jsonFile)); + } else if (/crud\/\d+$/.test(subpath) && req.method === 'DELETE') { + return res.json({ + status: 0, + msg: '删除成功' + }); + } else if (/download/.test(subpath)) { + return res.download(path.join(DIRNAME, 'download.zip')); + } + + res.json(readJson('notFound.json')); +}; function exist(subpath) { - return fs.existsSync(path.join(DIRNAME, subpath)); + return fs.existsSync(path.join(DIRNAME, subpath)); } function readJson(subpath) { - const content = fs.readFileSync(path.join(DIRNAME, subpath), 'utf8'); - return JSON.parse(content); + const content = fs.readFileSync(path.join(DIRNAME, subpath), 'utf8'); + return JSON.parse(content); } diff --git a/mock/index.js b/mock/index.js index 46828558c..a0bd27a30 100644 --- a/mock/index.js +++ b/mock/index.js @@ -26,7 +26,9 @@ module.exports = function (req, res) { res.status(500).json({status: 500, msg: err}); } else { res.set(result.headers); - if (!result.json) { + if (result.download) { + res.download(result.download); + } else if (!result.json) { res.status(result.statusCode).send(result.body); } else { res.status(result.statusCode).json(JSON.parse(result.body));