{"id":21708552,"url":"https://github.com/ufologist/backend-api","last_synced_at":"2026-05-21T14:19:38.494Z","repository":{"id":136686620,"uuid":"66528193","full_name":"ufologist/backend-api","owner":"ufologist","description":"一个用于与后端交互的数据层, 即统一地调用后端接口.","archived":false,"fork":false,"pushed_at":"2017-11-18T07:13:26.000Z","size":55,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-25T16:25:04.294Z","etag":null,"topics":["ajax","api","backend"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ufologist.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-25T05:38:29.000Z","updated_at":"2023-07-17T23:36:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"5219c69c-4bfa-4e52-bd9f-31dd2dd6ef9d","html_url":"https://github.com/ufologist/backend-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufologist%2Fbackend-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufologist%2Fbackend-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufologist%2Fbackend-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ufologist%2Fbackend-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ufologist","download_url":"https://codeload.github.com/ufologist/backend-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244660733,"owners_count":20489388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ajax","api","backend"],"created_at":"2024-11-25T22:27:47.666Z","updated_at":"2026-05-21T14:19:38.452Z","avatar_url":"https://github.com/ufologist.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# backend-api\n\n[![version][version]][source-url] ![size-image][size-image] [![changelog][changelog-image]][changelog-url] [![license][license-image]][license-url]\n\n[version]: https://img.shields.io/badge/v-1.1.0-blue.svg?style=flat-square\n[source-url]: https://github.com/ufologist/backend-api/blob/master/backend-api.js\n[license-image]: https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square\n[license-url]: https://github.com/ufologist/backend-api/blob/master/LICENSE\n[changelog-image]: https://img.shields.io/badge/CHANGE-LOG-blue.svg?style=flat-square\n[changelog-url]: https://github.com/ufologist/backend-api/blob/master/CHANGELOG.md\n[size-image]: http://img.badgesize.io/ufologist/backend-api/master/backend-api.js?compression=gzip\u0026style=flat-square\n\n一个用于与后端交互的数据层, 即统一地调用后端接口.\n\n## 功能\n\n* 统一配置接口/调用接口\n* 统一的调用接口前置处理\n* 统一的调用接口成功处理\n* 统一的调用接口错误处理\n\n## 为什么需要统一调用后端接口\n\n这样做的好处在于对前端架构做初略的(MVC)分层: 展现层(View) -\u003e 业务层(Controller) -\u003e 数据层(Model)\n\n展现层只需要知道自己要做什么事(这个所谓的事就是业务了)就可以了, 业务层来处理这个事情涉及到的业务流程. 例如展现层做注册, 那么展现层只要调用业务层提供的注册业务就好了, 不需要关心注册涉及到的业务逻辑. 这样各层做的事情就会职责分明, 具备单一职责原则, 各层配合也就清晰明了了, 代码逻辑自然理得很顺. 分层架构其实是在应对计算机领域经典的理论, 分解复杂度, 将复杂的事情分解为一件件相对简单的事, 各个击破.\n\n简而言之: 展现层(视图层)只需要关注调用什么业务, 业务层负责将数据从数据层中取出来, 数据层做最底层的后端交互.\n\n如果是比较简单的业务, 可以只需要视图层和数据层, 此时视图层承担了业务层的事情.\n\n例如下面的 MessageList 就相当于一个视图, 可以看作 Backbone 式的 MVC 模式\n\n注意: 我省略了构造 backendApi 的代码\n\n```javascript\nfunction MessageList() {\n    this.backendApi.invoke('getMessageList').then(this.render.bind(this));\n}\nMessageList.prototype.render = function(result) {\n    // 在这里解析数据渲染视图, 你可能会在这里使用前端模版库, 或者简单的拼字符串\n};\n```\n\n当然如果你想足够简单, 也可以完全使用 jQuery 式直接操作 DOM, 不抽象出视图\n\n```javascript\n$(function() {\n    function renderMessageList() {\n        this.backendApi.invoke('getMessageList').then(function(result) {\n            // 在这里解析数据渲染视图\n        });\n    }\n\n    renderMessageList();\n});\n```\n\n有一个统一的数据层, 即统一了数据输入和输出, 可以方便地做下面的事情\n\n* 方便统一处理一些公共的行为, 例如请求超时, 请求失败, 未授权等等\n* 方便知道前后端都使用了哪些接口\n* 方便扩展功能, 例如添加缓存层\n\n## 使用方法\n\n```html\n\u003c!-- 依赖 jQuery 或者 Zepto 提供底层的 ajax 功能, 推荐使用 Promise 模式 --\u003e\n\u003cscript src=\"http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"http://rawgit.com/ufologist/backend-api/master/backend-api.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n// 配置后端接口\nvar backendApi = new BackendApi({\n    'getMessageList': {\n        type: 'GET',\n        url: '/api/message'\n    },\n    'createMessage': {\n        type: 'POST',\n        url: '/api/message'\n    },\n    'getUserAgent': {\n        type: 'GET',\n        url: 'http://httpbin.org/user-agent'\n    }\n});\n// 设置统一的前置处理\nbackendApi.setBeforeSend(function(apiName, api, ajaxOptions) {\n    console.log('1 backendApi beforeSend', arguments);\n\n    var processedResult = {\n        allowSend: true,\n        result: null\n    };\n    return processedResult;\n});\n// 设置统一的成功处理\nbackendApi.setSuccessProcessor(function(result, textStatus, xhr) {\n    console.log('2.1 backendApi success', arguments);\n\n    var processedResult = {\n        success: true,\n        result: result\n    };\n    return processedResult;\n});\n// 设置统一的错误处理\nbackendApi.setError(function(xhr, error, textStatusOrResult) {\n    console.log('2.2 backendApi error', arguments);\n});\n\n// 调用后端接口\nbackendApi.invoke('getMessageList').then(function(result) {\n    console.log('createMessage', result);\n});\n\nbackendApi.invoke('createMessage', { // support full jQuery ajax options\n    data: {\n        title: 'msg title',\n        content: 'msg content'\n    }\n}).then(function(result) {\n    console.log('createMessage', result);\n});\n\nbackendApi.invoke('getUserAgent').then(function(result) {\n    console.log('getUserAgent', result);\n});\n\u003c/script\u003e\n```\n\n更多示例请参考 `test/spec` 目录下面的[测试用例](https://github.com/ufologist/backend-api/tree/master/test/spec)\n\n## 测试用例\n\n[运行测试用例](http://rawgit.com/ufologist/backend-api/master/test/index.html)\n\n![test-snapshot](http://rawgit.com/ufologist/backend-api/master/test/test-snapshot.png)\n\n## 参考\n\n* 项目经验\n\n  \u003e 在一些 SPA(Single Page App) 中, 做一个业务代理层(business delegate)用于调用后端接口.\n  \u003e\n  \u003e 此时需要统一处理一些事情\n  \u003e * 配置后端接口(区分本地模式和远程模式)\n  \u003e * 封装统一的请求参数, 例如版本号, 项目名等等\n  \u003e * 计算请求参数的签名, 并将所有参数加密(对称加密方式)后再传输\n  \u003e * 解密接口返回的数据\n  \u003e * 缓存接口数据(TTL方式, 分 Infinity 永久缓存和时效缓存, 以接口 URL 和请求参数的 hash 值做为缓存的 key)\n  \u003e * 统一处理错误码\n\n* [AmplifyJS](https://github.com/mikehostetler/amplify)\n\n  \u003e Request | Store | Pub/Sub\n  \u003e\n  \u003e AmplifyJS solves the following problems:\n  \u003e * **Ajax Request Management**\n  \u003e \n  \u003e   `amplify.request` provides a clean and elegant request abstraction for all types of data, even allowing for transformation prior to consumption.\n  \u003e\n  \u003e   ```javascript\n  \u003e   amplify.request.define('ajaxExample1', 'ajax', {\n  \u003e       url: '/myApiUrl',\n  \u003e       dataType: 'json',\n  \u003e       type: 'GET'\n  \u003e   });\n  \u003e   \n  \u003e   amplify.request('ajaxExample1', function(result) {\n  \u003e       console.log(result);\n  \u003e   });\n  \u003e   ```\n  \u003e\n  \u003e * **Client Side Component Communication**\n  \u003e\n  \u003e   `amplify.publish/subscribe` provides a clean, performant API for component to component communication.\n  \u003e\n  \u003e * **Client Side Browser \u0026 Mobile Device Storage**\n  \u003e\n  \u003e   `amplify.store` takes the confusion out of HTML5 localStorage. It doesn't get simpler than using amplify.store(key, data)! It even works flawlessly on mobile devices.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fufologist%2Fbackend-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fufologist%2Fbackend-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fufologist%2Fbackend-api/lists"}