商汇粹外网资源平台

搜索
查看: 1561|回复: 5

如何在 Github 上做一个规范的开源项目?

[复制链接]

该用户从未签到

2

主题

2

帖子

38

积分

新手上路

Rank: 1

积分
38
发表于 2022-10-22 09:50:09 | 显示全部楼层 |阅读模式
很多人 Github 当成一个代码仓库,需要代码就到上面去搜索,但是很多项目都是扔上去就再也不管了,也没有文档,很不利于别人使用。
而我理解的开源项目应该是要对他人有用的,且易于使用的。
那么一个优秀的开源项目应该有哪些特性?
如何规范开源项目?
开源者应该如何维护开源项目?

还望各位不吝赐教,谢谢!
回复

使用道具 举报

该用户从未签到

1

主题

12

帖子

70

积分

注册会员

Rank: 2

积分
70
发表于 2022-10-22 10:08:29 | 显示全部楼层
轮子哥也回答了这个问题,让我倍感压力。但还是硬着头皮把我自己维护了一两年(放到Github上才两三个月,以前是在自己的Git服务器上)的自用爬虫框架拿出来,并说说自己对开源项目的理解。PS:最近有了其他contributors。
爬虫框架的Github地址:
xianhu/PSpider,最近刚刚补充了英文文档说明(写起来那个痛苦呀)。
写这个框架的初衷有这么几个:
1. 学习Python基础,学习Python进阶用法,比如装饰器、元类、异步IO、多线程&数据同步等。
2. 不喜欢用轮子,更喜欢造轮子,因为可以自己很方便的扩展、修改框架。
3. 写爬虫框架的过程,能更好的理解爬虫框架的内部原理、数据流程等,而不是仅仅会用。
下面回答下题主提问的几个问题:
一个优秀的开源项目应该有哪些特性?
很明显我的开源项目不优秀,但我看过一些其他的优秀的开源项目,比如aiohttp,tushare等。个人认为一个优秀的爬虫框架应该包含如下特性:
(1)开源项目完成的功能很明确,且有完整的说明文档。小的、简单的开源项目,最好还能讲解一下项目架构,代码结构等。
(2)开源项目的代码结构清晰,代码抽象合理,文件名、变量名等命名合理易读。某一语言的项目最好遵循该语言的代码规范,比如Python的PEP 8或者GooglePythonStyleGuide,或者利用pylint等第三方检查库进行项目检查。
(3)开源项目的功能要具有通用性,比如各平台通用、各语言版本通用、各业务情形通用。这点要求就比较高,可能需要大量的测试人员去不断debug。
(4)有持续的贡献者,有持续的更新,有人对其负责。在Github上找开源项目时,如果最后更新日期在一两年前,我一般不会使用。
很明显,我的开源项目只符合30%到50%左右,哎,道路漫长。
如何规范开源项目?
开源项目的重点在于开源两字,如何规范确实比较头疼。据我了解,Hadoop的每次分支合并,都会有上千人进行评估,且评估者涉及各行各业各个职位(不知道是真是假)。当然Hadoop那种级别的开源项目另当别论,当开源项目不是那么庞大时,可能相对来说简单一点。
规范开源项目有两个方面需要考虑:
(1)对于开源者本身来说,需要规范代码结构,规范文件名、变量名、函数名、类名等等,不能随随便便更改接口,要做到向下兼容,特别是当你的项目被别人使用时。(说起来容易,做起来还是挺难的)
(2)当你的开源项目被别人fork且提交了合并请求时,作为开源者,应该去检查这次commit的合理性、规范性、通用性等,因为你最了解你的项目。比如检查文件、变量命名是否合理,考虑的情况是否全面,合并后是否对于其他模块产生影响等等。由于提交合并的开发者水平不一、风格不一、考虑问题的角度也不一样,如果随随便便就去合并每一个人的提交,很容易造成开源项目混乱。当然,当你拒绝一个提交时,最好给出一个合理的解释,以免对提交者产生坏的影响。
开源者应该如何维护开源项目?
(1)规范、规范、规范。这点很重要,对开源者和贡献者都要求很高。
(2)如果条件允许,最好和所有贡献者建立讨论小组,每周或每月组织讨论,共同维护。
(3)要宣传自己的项目,不要怕被鄙视,要让更多的人使用。只有这样才能发现项目的问题,以及项目所需要进一步开发的功能等。
回复

使用道具 举报

该用户从未签到

2

主题

11

帖子

33

积分

新手上路

Rank: 1

积分
33
发表于 2022-10-22 10:26:49 | 显示全部楼层
这篇关于项目规范的文章,在我正在写回复的时候已经有接近9000的star了,对一个规范的项目有非常好的指导意义。指导大家仔细阅读。
wearehive/project-guidelines
项目规范 ·

a

javascript工程项目的一系列最佳实践策略
每当开发一个新项目,就像在田里打滚,对其他人来说维护这样一个项目简直就是一个潜在的噩梦。以下内容是我们在hive的大多数JavaScript项目中发现,撰写和收集的最佳实践列表(至少我们是这样认为的)。如果您想分享其他最佳实践,或者认为其中一些内容应该删除。欢迎随时与我们分享。.


  • Git

    • 一些git规则
    • Git workflow
    • 编写良好的提交备注信息




  • 文档
  • 环境

    • 一致的开发环境
    • 一致性的依赖配置




  • 依赖
  • 测试
  • 结构与命名规则
  • 代码风格
  • 日志
  • API

    • API 设计
    • API 安全
    • API 文档




  • 许可


1. Git





a

1.1 一些Git规则

有一套规则要牢记:

  • 在需求分支中执行开发工作。
为什么:
因为这样,所有的工作都是在专用的分支而不是在主分支上隔离完成的。它允许您提交多个pull请求而不会导致代码冲突。您可以持续迭代提交,而不会污染那些很可能还不稳定而且还未完成代码的主分支。更多请阅读...

  • 从develop拉出分支。
为什么:
这样,您可以保持master中的代码稳定性,这样就不会导致构建问题,并且可以直接用于发版(当然,这可能对某些项目来说要求会比较高).

  • 在确保Pull请求之前,千万不要push到 develop 或者 master 分支。
为什么:
开发成员如果完成功能,需要马上通知团队。这样开发伙伴就开源更容易对代码进行评审,同时还可以互相讨论所开发的需求功能

  • 在更新您本地的develop分支时,并在push和pull之前,先进行rebase操作。
为什么:
Rebasing将合并到你正在操作的分支(master或develop)中,并将您本地进行的提交应用于所有历史提交的最顶端,而不会去创建额外的merge提交(假设没有冲突的话)。这样可以保持一个漂亮而干净的历史提交记录。 更多请阅读 ...

  • 请确保在pull rebase的时候解决完潜在的冲突。
  • merge后删除本地和远程需求分支。
为什么:
如果不删除需求分支,会导致大量僵尸分支存在,会很混乱。请确保一次性合并到 (master or develop)。只有当这个feature需求分支还处于开发中时才应该存在。

  • 在进行Pull请求之前,请确保您的需求分支已经建立,并已经通过了所有的测试(包括代码规则检查)。
为什么:
您即将将代码提交到这个稳定的分支。而如果您的需求分支功能测试都失败了,那您的目标分支构建很可能也会失败。此外,确保在进行pull请求之前应用代码规则检查。因为它有助于我们代码的可读性,并减少格式化的代码与实际业务代码更改混合在一起导致的混乱问题。

  • 使用 .gitignore 文件.
为什么:
此文件包含一个文件列表描述,描述那些文件和代码不会被发送到远程git仓库中。这个文件里面应该添加那些为大多数IDE自己产生的文件和文件夹以及大多数常见的依赖文件夹和文件(比npm的node_modules),这些文件我们都不会上传到远程代码库,这些文件不是我们需要的。

  • 保护 develop 和 master 分支.
为什么:
它保护您的生产分支免受意外情况和不可回退的变更. 更多请阅读... Github and Bitbucket


1.2 Git workflow

因为以上原因, 我们使用 需求功能分支-workflow 并配合 Rebasing的使用方法 和 一些关于 Gitflow (命名和使用一个develop branch). 主要步骤如下:

  • 针对一个新项目, 在你的项目目录初始化你的项目. 针对下级目录 features/changes 这一步请忽略.
cd <项目目录>
git init

  • Checkout 一个新的 feature/bug-fix 分支。
git checkout -b <分支名称>

  • 新增一下代码变更。
git add
git commit -a
为什么:
git commit -a 这会启动一个编辑器,编辑你的说明信息,这样的好处是可以专注于写这些注释说明. 更多请阅读 section 1.3.

  • 保持与远程的同步,以便拿到最新变更。
git checkout develop
git pull
为什么:
这其实是在rebasing的时候创造了一个解决冲突的时机,而不是创建通过包含冲突的Pull请求。

  • 通过使用rebase从develop拉取最新的代码提交
git checkout <branchname>
git rebase -i --autosquash develop
为什么:
您可以使用--autosquash将所有相同类型提交压缩到单个提交。一般没有人想在开发分支中提交一大堆相同功能的提交吧? 更多请阅读...

  • 如果没有冲突请跳过此步骤,如果你有冲突, 解决方式 就可以通过--continue参数继续rebase
git add <file1> <file2> ...
git rebase --continue

  • Push你的分支. Rebase将会改变提交历史, 所以你可以使用 -f 强制push到远程分支. 如果其他人正在您的这个分支上面进行开发,请使用不那么破坏性的 --force-with-lease.
git push -f
为什么:
当你rebase时,你会改变需求功能分支的提交历史。结果呢?Git却拒绝了正常的“git push”。那么,您只能使用-f或--force参数了。更多请阅读...

  • 提交一个Pull Request.
  • Pull Request 会被负责代码审查的同事接受,合并和关闭.
  • 如果你完成了开发,请记得删除你的本地分支.
git branch -d <分支>
删除所有已经不在远程仓库维护的分支
git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done


1.3 如何写好提交说明

坚持遵循关于提交的标准指南,会让在与他人合作使用Git时更容易。这里有一些经验法则 (source):

  • 将标题和文体用换行后的两条空行分开
为什么:
Git非常聪明,它可将您提交消息的第一行识别为摘要。实际上,如果你尝试使用git shortlog,而不是git log,你会看到一个很长的提交消息列表,其中包含提交的id和摘要。

  • 将标题行限制为50个字符,并将文体控制在72个字符。
为什么_
提交应尽可能简洁明了,而不是写一堆冗余的描述。 更多请阅读...

  • 大写的标题线
  • 不要用句号结束标题句
  • 使用 imperative mood 在标题线
为什么:
不是简单的写提交者这次做了什么。最好写明提交者将要进一步做什么事情。更多请阅读...

  • 使用文体去解释 是什么为什么 而不是 怎么做


2. 文档



a


  • 使用这个 模板 给 README.md, 欢迎添加里面没有的内容。
  • 对于具有多个存储库的项目,请在各自的README.md文件中提供它们的链接。
  • 随项目持续的更新 README.md.
  • 给你的代码添加详细的注释,这样就可以清楚每个主要部分的含义。
  • 如果您正在使用的某些代码和方法,在github或stackoverflow上已经有公开讨论,请在您的评论中包含这些链接,
  • 不要把注释作为坏代码的借口。保持你的代码干净整洁。
  • 也不要把那些清晰的代码作为不写注释的借口。
  • 当代码更新,也请确保注释的同步更新。


3. 环境



a


  • 如果需要,请分别定义 development, test 和 production 三个环境.
为什么:
不同的环境可能需要不同的数据,token,API,端口等。您可能需要一个隔离的development环境,它调用mock的API,mock会返回我们需要的数据,使自动和手动测试变得更加容易。或者您可能只想在production 环境中才启用Google Analytics(分析)。 更多请阅读...

  • 从环境变量加载部署的相关配置,不要将这些配置作为常量添加到代码库中, 看这个例子.
为什么:
你会有令牌,密码和其他有价值的信息。这些配置应正确地从应用程序内部分离开来,这样代码库就可以随时独立发布,不会包含这些敏感配置信息。
怎么做:
使用.env文件来存储环境变量,并将不提交到git仓库的文件添加到.gitignore中。另外,再提交一个.env.example作为开发人员的参考配置。对于生产环境,您应该以标准化的方式设置环境变量。 更多请阅读

  • 建议您在应用程序启动之前校验一下环境变量。 看这个例子 使用 joi 去校验提供的值.
为什么:
在排查问题的痛苦经历中你一定需要他。


3.1 一致的开发环境:


  • 在package.json里的engines中设置你的node版本
为什么:
让其他人可以清晰的知道这个项目中用的什么node版本 更多请阅读...

  • 另外,使用nvm并在你的项目根目录下创建一个.nvmrc文件。不要忘了在文档中标注。
为什么:
任何使用nvm的人都可以使用nvm use来切换到自己想要的node版本。 更多请阅读...

  • 最好设置一个检查node和npm版本的“preinstall”脚本
为什么:
某些依赖项可能会在新版本的npm中安装失败。

  • 如果可以的话最好使用Docker image
为什么:
它可以在整个工作流程中为您提供一致的环境。不用花太多的时间来解决依赖或配置。 更多请阅读...

  • 使用本地模块,而不是使用全局安装的模块
为什么:
你不能指望你的同事在自己的全局环境都安装了相应的模块,本地模块可以方便你分享你的工具。


3.2 依赖一致性:


  • 确保您的团队成员获得与您完全相同的依赖关系
为什么:
因为您希望代码在任何开发环境中运行都能像预期的一样 更多请阅读...
怎么做:
在npm@5或者更高版本中使用 package-lock.json
我们没有npm@5:
或者,您可以使用“yarn”,并确保在“README.md”中标注。您的锁文件和package.json在每次依赖关系更新后应该具有相同的版本。更多请阅读...
我不太喜欢 Yarn:
居然不喜欢Yarn,太糟糕了。对于旧版本的“npm,在安装新的依赖关系时使用-save --save-exact,并在发布之前创建npm-shrinkwrap.json。 更多请阅读...


4. 依赖



a


  • 持续跟踪你当前的可用依赖包: e.g., npm ls --depth=0. 更多请阅读...
  • 查看这些软件包是否已经变得不可用或者已经废弃: depcheck. 更多请阅读...
为什么:
您可能会在代码中包含未使用的库,这会增大生产包的大小。请搜索出这些未使用的依赖关系并摆脱它们吧。

  • 在使用依赖之前,请检查他的下载统计信息,看看它是否被社区大量使用: npm-stat. 更多请阅读...
为什么:
更多的使用将意味着更多的贡献者,这通常意味着拥有更好的维护,这些才能确保快速发现错误和快速修复错误。

  • 在使用依赖关系之前,请检查它是否具有良好而成熟的版本发布频率与大量的维护者:例如, npm view async. 更多请阅读...
为什么:
如果维护者没有足够快地merge修补程序,那么这些贡献者也将会变得不积极不高效。

  • 如果需要使用那些不太熟悉的依赖包,请在使用之前与团队进行充分讨论。始终确保您的应用程序在最新版本的依赖包上面能正常运行,而不是无法使用:npm outdated. 更多请阅读...
为什么:
依赖关系更新有时包含破坏性更改。当显示需要更新时,请始终先查看其发行说明。并逐一的更新您的依赖项,如果出现任何问题,可以使故障排除更容易。这里有一个很酷的工具,如 npm-check-updates.

  • 检查包是否有已知的安全漏洞,例如: Snyk.


5. 测试



a


  • 如果需要,构建一个 test 环境.
为什么:
虽然有时在production模式下端到端测试可能看起来已经足够了,但有一些例外:比如您可能不想在生产环境下启用数据分析功能,只能用测试数据来填充(污染)某人的仪表板。另一个例子是,您的API可能在production中才具有速率限制,并在请求达到一定量级后会阻止您的测试请求。

  • 将测试文件放在使用* .test.js或* .spec.js命名约定的测试模块,比如moduleName.spec.js
为什么:
你肯定不想进入一个层次很深的文件夹结构来查找里面的单元测试。更多请阅读...

  • 将其他测试文件放入独立的测试文件夹中以避免混淆。
为什么:
一些测试文件与任何特定的文件实现没有特别的关系。你只需将它放在最有可能被其他开发人员找到的文件夹中:__test__文件夹。这个名字:__test__也是现在的标准,被大多数JavaScript测试框架所接受。

  • 编写可测试代码,避免不良代码,提取并写成纯函数 //UFO
为什么:
您想要将业务逻辑拆分为为单独的测试单元。您必须“尽量减少不可预测性和非确定性过程对代码可靠性的影响”。 更多请阅读...
纯函数是一个函数,它总是为相同的输入返回相同的输出。相反,不纯的函数是可能具有不可预测性或取决于来自外部的条件来决定产生对应的输出值。这使得它不那么可预测更多请阅读...


  • 使用静态类型检查器
为什么:
有时您可能需要一个静态类型检查器。它为您的代码带来一定程度的可靠性。更多请阅读...

  • 先在本地develop分支运行测试,待测试通过后,再进行pull请求。
为什么:
你不想成为一个导致生产分支构建失败的人吧。在您的rebase之后运行测试,然后再将您的需求功能分支改动推送到远程仓库。

  • 记录您的测试,包括在README.md文件中的相关部分说明。
为什么:
这个记录的笔记非常的方便,便于留给其他开发人员或DevOps专家及QA和任何幸运的人,让他们更方便的来处理您的代码。


6. 结构布局与命名



a


  • 围绕产品功能/页面/组件来组织您的文件,而不是围绕角色来组织文件。此外,请将测试文件放在他们对应实现的旁边。
不规范
.
├── controllers
|   ├── product.js
|   └── user.js
├── models
|   ├── product.js
|   └── user.js

规范
.
├── product
|   ├── index.js
|   ├── product.js
|   └── product.test.js
├── user
|   ├── index.js
|   ├── user.js
|   └── user.test.js

为什么:
比起一个冗长的列表文件,创建一个单一责权封装的小模块,并在其中包括测试文件。将会更容易浏览,更一目了然。

  • 将其他测试文件放在单独的测试文件夹中以避免混淆。
为什么:
这样可以节约您的团队中的其他开发人员或DevOps专家的时间。

  • 使用./config文件夹,不要为不同的环境制作不同的配置文件。
为什么:
当您为不同的目的(数据库,API等)分解不同的配置文件;将它们放在具有容易识别名称(如“config”)的文件夹中才是有意义的。只要记住不要为不同的环境制作不同的配置文件。这样并不是具有扩展性的做法,如果这样,就会导致随着更多应用程序部署被创建出来,新的环境名称也会不断被创建,非常混乱。 配置文件中使用的值应通过环境变量提供。 更多请阅读...

  • 将脚本文件放在./scripts文件夹中。包括bash脚本和node脚本。 为什么:
很可能最终会出现很多脚本文件,比如生产构建,开发构建,数据库feeders,数据库同步等。

  • 将构建输出结果放在./build文件夹中。将build/添加到.gitignore中以便忽略此文件夹。
为什么:
命名为你最喜欢的就行,dist看起来蛮酷的。但请确保与您的团队保持一致性。哪些东西最有应该放这个文件夹呢?比如(bundle,编译结果,转换结果)。您产生什么编译结果,您的队友也可以生成同样的结果,所以没有必要将这些结果提交到远程仓库中。除非你故意希望提交上去。

  • 文件名和目录名请使用PascalCase``camelCase风格。组件请使用PascalCase风格。
  • CheckBox/index.js应该代表CheckBox组件,也可以写成CheckBox.js,但是不能写成冗长的CheckBox/CheckBox.js或checkbox/CheckBox.js。
  • 理想情况下,目录名称应该和index.js的默认导出名称相匹配。
为什么:
这样您就可以通过简单地导入其父文件夹直接使用你预期的组件或模块。


7. 代码风格



a


  • 对新项目请使用Stage2和更高版本的JavaScript(现代化)语法。对于老项目,保持与老的语法一致,除非您打算把老的项目也更新为现代化风格。
为什么:
这完全取决于你的选择。我们使用转换器来使用新的语法糖。Stage2更有可能最终成为规范的一部分,而且仅仅只需经过小版本的迭代就会成为规范。

  • 在构建过程中包含代码风格检查。
为什么:
在构建时中断下一步操作是一种强制执行代码风格检查的方法。强制你认真对待代码。请确保在客户端和服务器端代码都执行代码检查。 更多请阅读...

  • 使用 ESLint - Pluggable JavaScript linter 去强制执行代码检查
为什么:
我们个人很喜欢eslint,不强制你也喜欢。它支持更多的规则,配置规则的能力和添加自定义规则的能力。

  • 针对JavaScript我们使用Airbnb JavaScript Style Guide , 更多请阅读. 在你的团队和项目中推广此代码风格是必须的。
  • 我们使用 ESLint的流式样式检查规则。 如果使用FlowType.
为什么:
Flow引入了很少的语法,需要遵循这些代码风格并进行检查。

  • 使用.eslintignore将某些文件或文件夹从代码风格检查中排除。
为什么:
当您需要从风格检查中排除几个文件时,就再也不需要通过eslint-disable注释来污染您的代码了。

  • 在Pull Request之前,请删除任何eslint的禁用注释。
为什么:
在处理代码块时禁用风格检查是正常现象,这样就可以关注在业务逻辑。只要记住把那些eslint-disable注释删除并遵循这些风格规则。

  • 根据任务的大小使用//TODO:注释或做一个标签。
为什么:
这样你就可以提醒自己和他人有这样一个小的任务需要处理(如重构一个函数或更新一个注释)。对于较大的任务,使用由lint规则执行的//TODO(#3456),其中的#3456号码是一个标签,方便查找。

  • 随着代码的变化,始终保持注释的相关性。删除那些注释掉的代码块。
为什么:
代码应该尽可能的可读,你应该摆脱任何分心的事情。如果你在重构一个函数,就不要注释那些旧代码,直接把要注释的代码删除吧。

  • 避免不相关的和搞笑的的注释,日志或命名。
为什么:
虽然您的构建过程中可能(应该)移除它们,但有可能您的源代码会被移交给另一个公司/客户,你的这些笑话应该无法逗乐你的客户。

  • 请使用有意义容易搜索的命名,避免缩写名称。对于函数使用长描述性命名。功能命名应该是一个动词或动词短语,需要能清楚传达意图的命名。
为什么:
它使读取源代码变得更加自然。

  • Organize your functions in a file according to the step-down rule. Higher level functions should be on top and lower levels below.(译者注:这一段我翻译不好,大家看看原文吧,大体意思是为了说明函数的组织方式,根据逐级下降的规则,把底层函数和上层函数按照具有具有条理性的规则拆分开。也有朋友说这个是高阶函数的封装。此中文翻译已经被官方采纳,我们等hive的同事给出进一步解释吧。也请读者给出您的宝贵建议。)
为什么:
它使源代码的可读性更好。


8. 日志



a


  • 避免在生产环境中使用客户端的日志
为什么:
您在构建过程可以把(应该)它们去掉,但是请确保您在代码风格检查中提供了有关控制台日志的警告信息。

  • 用于生产环境的可读生产日志记录。一般使用在生产模式下所使用的日志记录库 (比如 winston or node-bunyan).
为什么:
它通过添加着色、时间戳、log到控制台或者文件中,来减少故障排除中那些令人不愉快的事情,这些文件会每天滚动迭代。更多请阅读...


9. API



a



9.1 API 设计

为什么:
因为我们试图实施开发出结构稳健的Restful接口,让团队成员和客户可以简单而一致地使用它们。
为什么:
缺乏一致性和简单性会大大增加集成和维护的成本。这就是为什么API设计这部分会包含在这个文档中的原因


  • 我们主要遵循资源导向的设计方式。它有三个主要要素:资源,集合和URLs。

    • 资源具有数据,嵌套,和一些操作方法。
    • 一组资源称为一个集合。
    • URL标识资源或集合的在线位置。

为什么:
这是针对开发人员(您的主API使用者)非常著名的设计方式。除了可读性和易用性之外,它还允许我们在无需了解API细节的情况下编写通用库和一些连接器。

  • 使用kebab模式的URL。
  • 在查询字符串或资源字段中使用camelCase模式。
  • 在URL中使用多个kebab-case作为资源名称。
  • 总是使用复数名词来命名指向一个集合的url:/users.
为什么:
基本上,它可读性会更好,并可以保持URL的一致性。 更多请阅读...

  • 在源代码中,将复数转换为具有列表后缀名描述的变量和属性。
为什么_:
复数形式的URL非常好,但在源代码中使用它却很微妙而且容易出错,所以要小心谨慎。

  • 坚持这样一个概念:始终以集合名起始并以标识符结束。
/students/245743
/airports/kjfk


  • 避免这样的网址:
GET /blogs/:blogId/posts/:postId/summary

为什么:
这不是在指向资源,而是在指向属性。您完全可以将属性作为参数传递,以减少响应。

  • URLs里面请尽量少用动词
为什么:
因为如果你为每个资源操作使用一个动词,你很快就会维护一个很大的URL列表,而且没有一致的使用模式,这会使开发人员难以学习。此外,我们还要使用动词做别的事情。

  • 为非资源型请求使用动词。在这种情况下,您的API并不需要返回任何资源。而是去执行一个操作并返回执行结果。这些不是 CRUD(创建,查询,更新和删除)操作:
/translate?text=Hallo

为什么:
因为对于CRUD,我们在资源或集合URL上使用HTTP自己带的方法。我们所说的动词实际上是指Controllers。你通常不会开发这些东西。更多请阅读...

  • 请求体或响应类型如果是JSON,那么请遵循camelCase规范为JSON属性命名来保持一致性。
为什么:
这是一个JavaScript项目指南,其中用于生成JSON的编程语言以及用于解析JSON的编程语言被假定为JavaScript。

  • 即使资源类似于对象实例或数据库记录这样的单一概念,您也不应该将table_name用作资源名称或将column_name作为资源属性。
为什么:
因为您的目的是分析资源,而不是分析数据库模式。

  • 再次,只有在您的URL上面命名资源时才使用名词,不要尝试解释其功能。
为什么:
只能在资源URL中使用名词,避免像/addNewUser或/updateUser这样的结束点。也避免使用参数作为发送资源的操作。

  • 如何使用HTTP方法来操作CRUD功能
怎么做:
GET: 查询资源的表示法
POST: 创建一些新的资源或者子资源
PUT: 更新一个存在的资源
PATCH: 更新现有资源。它只更新所提供的字段,不管其他字段
DELETE:        删除一个存在的资源


  • 对于嵌套资源,请在URL中把他们的关系表现出来。例如,使用id将员工与公司联系起来。
为什么:
这是一种自然的方式,方便资源的认知。
怎么做:
GET /schools/2/students , 应该从学校2得到所有学生的名单
GET /schools/2/students/31        , 应该得到学生31的详细信息,且此学生属于学校2
DELETE /schools/2/students/31        , 应删除属于学校2的学生31
PUT /schools/2/students/31        , 应该更新学生31的信息,仅在资源URL上使用PUT方式,而不要用收集
POST /schools , 应该创建一所新学校,并返回创建的新学校的细节。在集合URL上使用POST


  • 对于具有v前缀(v1,v2)的版本,使用简单的序数。并将其移到URL的左侧,使其具有最高的范围表述:
http://api.domain.com/v1/schools/3/students       

为什么:
当您的API为第三方公开时,升级API会导致发生一些意料之外的影响,也可能导致使用您API的人无法使用你的服务和产品。而这时使用URL中版本化可以防止这种情况的发生。 更多请阅读...

  • 响应消息必须是自我描述的。一个很好的错误消息响应可能如下所示:
{
    "code": 1234,
    "message" : "Something bad happened",
    "description" : "More details"
}
或验证错误:
{
    "code" : 2314,
    "message" : "Validation Failed",
    "errors" : [
        {
            "code" : 1233,
            "field" : "email",
            "message" : "Invalid email"
        },
        {
            "code" : 1234,
            "field" : "password",
            "message" : "No password provided"
        }
      ]
}
为什么:
开发人员在使用这些由API构建的应用程序时,难免会需要在故障排除和解决问题的关键时刻使用到这些精心设计的错误消息。好的错误消息设计能节约大量的问题排查时间。
_注意:尽可能保持安全异常消息的通用性。例如,别说不正确的密码,您可以换成无效的用户名或密码,以免我们不知不觉地通知用户他的用户名确实是正确的,只有密码不正确。这会让用户很懵逼。


  • 只使用这8个状态代码,并配合您自定义的响应描述来表述程序工作一切是否正常客户端应用程序发生了什么错误API发生错误
选谁呢?:
200 OK GET, PUT 或 POST 请求响应成功.
201 Created 标识一个新实例创建成功。当创建一个新的实例,请使用POST方法并返回201状态码。
304 Not Modified 发现资源已经缓存在本地,浏览器会自动减少请求次数。
400 Bad Request 请求未被处理,因为服务器不能理解客户端是要什么。
401 Unauthorized 因为请求缺少有效的凭据,应该使用所需的凭据重新发起请求。
403 Forbidden 意味着服务器理解本次请求,但拒绝授权。
404 Not Found 表示未找到请求的资源。
500 Internal Server Error 表示请求本身是有效,但由于某些意外情况,服务器无法实现,服务器发生了故障。
为什么:
大多数API提供程序仅仅只使用一小部分HTTP状态代码而已。例如,Google GData API仅使用了10个状态代码,Netflix使用了9个,而Digg只使用了8个。当然,这些响应作为响应主体的附加信息。一共有超过70个HTTP状态代码。然而,大多数开发者不可能全部记住这70个状态码。因此,如果您选择不常用的状态代码,您将使应用程序开发人员厌烦构建应用程序,然后你还要跑到维基百科上面找出您要告诉他们的内容,多累啊。 更多请阅读...

  • 在您的响应中提供资源的总数
  • 接受limit和offset参数
  • 还应考虑资源暴露的数据量。 API消费者并不总是需要资源的完整表述。可以使用一个字段查询参数,该参数用逗号分隔的字段列表来包括:
GET /student?fields=id,name,age,class


  • 分页,过滤和排序功能并不需要从所有资源一开始就要得到支持。记录下那些提供过滤和排序的资源。


9.2 API 安全

这些是一些基本的安全最佳实践:

  • 不要只使用基本认证。不要在URL中传输验证令牌:GET /users/123?token=asdf....
为什么:
因为令牌、用户ID和密码通过网络是明文传递的(它是base64编码,而base64是可逆编码),所以基本认证方案是不安全的。 更多请阅读...

  • 必须使用授权请求头在每个请求上发送令牌:Authorization: Bearer xxxxxx, Extra yyyyy
  • 授权代码应该是简短的。
  • 通过不响应任何HTTP请求来拒绝任何非TLS请求,以避免任何不安全的数据交换。响应403 Forbidden的HTTP请求。
  • 考虑使用速率限制
为什么:
保护您的API免受每小时数千次的机器人扫描威胁。您应该考虑在早期就实施流控。

  • 适当地设置HTTP请求头可以帮助锁定和保护您的Web应用程序。更多请阅读...
  • 您的API应将收到的数据转换为规范形式,或直接拒绝响应,并返回400错误,并在其中包含有关错误或丢失数据的详细信息。
  • 所有通过Rest API交换的数据必须由API来校验。
  • 序列号JSON
为什么:
JSON编码器的一个关键问题是阻止浏览器中输入的任意JavaScript代码在远程被执行,或者如果您在服务器上使用node.js。您必须使用适当的JSON序列化程序对用户输入的数据进行正确编码,以防止在浏览器上执行用户提供的输入,这些输入可能会包含恶意代码,而不是正常的用户数据。

  • 验证内容类型,主要使用application/*.json(Content-Type 头字段).
为什么:
例如,接受application/x-www-form-urlencodedMIME类型可以允许攻击者创建一个表单并触发一个简单的POST请求。服务器不应该假定Content-Type。缺少Content-Type请求头或异常的Content-Type请求头应该让服务器直接以4XX响应内容去拒绝请求。


9.3 API 文档


  • 在[README.md模板](./README.sample.md)为API填写 API参考段落。
  • 尽量使用示例代码来描述API授权方法
  • 解释URL的结构(仅path,不包括根URL),包括请求类型(方法)
对于每个端点(endpoint)说明:

  • 如果存在URL参数就使用URL参数,请根据URL中使用到的名称来指定它们:
Required: id=[integer]
Optional: photo_id=[alphanumeric]


  • 如果请求类型为POST,请提供如何使用的示例。URL Params也是这样。Params分为可选和必需。
  • 响应成功,应该对应什么样的状态代码,返回了哪些数据?当人们需要知道他们的回调应该是期望的样子,这很有用:
Code: 200
Content: { id : 12 }


  • 错误响应,大多数端点都存在许多失败的可能。比如错误参数导致的未经授权的访问等。所有的都应该列在这里。虽然有可能会重复,但它却有助于防止发生损害。例如
{
    "code": 403,
    "message" : "Authentication failed",
    "description" : "Invalid username or password"
}

  • 使用API设计工具,有很多开源工具可用于提供良好的文档,例如 API Blueprint and Swagger.


10. 证书



a

确保您有权使用的这些资源。如果您使用其中的软件库,请记住先查询MIT,Apache或BSD,但如果您打算修改它们,请查看许可证详细信息。图像和视频的版权可能会导致法律问题。
资源: RisingStack Engineering, Mozilla Developer Network, Heroku Dev Center, Airbnb/javascript, Atlassian Git tutorials, Apigee, Wishtack
回复

使用道具 举报

该用户从未签到

5

主题

12

帖子

51

积分

注册会员

Rank: 2

积分
51
发表于 2022-10-22 10:45:09 | 显示全部楼层
分享一款程序员朋友开发的可视化水印制作工具, 在github已完全开源, 是一款非常适合学习参考的前端项目
回复

使用道具 举报

该用户从未签到

4

主题

13

帖子

49

积分

新手上路

Rank: 1

积分
49
发表于 2022-10-22 11:03:29 | 显示全部楼层
规范的Web前端开源项目需要

  • 版本管理:每个版本的发布必须有 releases 且遵循 语义化版本 2.0.0
  • 发布:将构建后的代码发布到 npm 或者 dist/ 文件夹下存放UMD规范代码
  • 使用示例:示例可以放在 /example 目录下
  • 文档: 尽量放在 /doc 目录下,文档应给出组件/库的最佳实践
  • 单元测试: 可以放在 /test 目录下

https://travis-ci.org/  是个好帮手
回复

使用道具 举报

该用户从未签到

1

主题

11

帖子

45

积分

新手上路

Rank: 1

积分
45
发表于 2022-10-22 11:21:49 | 显示全部楼层
目录
<!-- START doctoc -->
​  目录折叠

</details> <!-- START doctoc -->
eggos目录环境准备第一种直接docker安装第二种dockerfile下载eggos安装qemu虚拟机启动qemu虚拟机体验eggosJavaScript解释器退出、重新进入文件系统验证HTTP服务NES模拟器镜像扩展阅读
环境


  • Windows11(环境无所谓)
  • docker(版本无所谓)
准备

  你可以选择直接push远程打包好的eggos-ubuntu镜像,这样的话,可以不用下面的步骤
docker pull 3293172751/cubos-ubuntu:1.0.2


  强推的教程:

  • docker教程
  • Go语言教程
  • linux教程
二种安装方式,一种是直接docker pull拉取镜像,第二种就是使用dockerfile,建议第二种。
第一种直接docker安装

使用docker安装Ubuntu(可以不用设置容器映射,直接push即可)
docker run -it exec --name ubuntu-eggos ubuntu /bin/bash
……. 安装vim、go、git等等等等基本工具,哎呀反正挺麻烦的,如果你不是选择直接pull我的镜像到本地,建议直接用dockerfile方式
# 虚拟机可以直接用sudo root 进入root用户,Linux教程中有设置root密码教程 apt-get install vim apt-get install git apt-get install golang apt-get install net-tools  # 这个还需要安装一个net-tools 因为ipconfig 需要


第二种dockerfile

使用dockerfile直接安装镜像,⚡推荐使用


  需求
我们所需要的镜像中,不含有vim/ifconfig/golang等命令,所以我们需要重新按照那些命令
docker commit
对于简单的可能会是一个很好的选择,但是对于随时变化的镜像来说,特别麻烦
可不可以一次性搞定?
某种镜像的增强,给我list做个清单,后续我加入任何功能,直接在list单子里面run,相当于多次提交
一次性添加,一次性成型。那么你就可以选择相信dockerfile  


下载eggos

直接使用ISO镜像来启动eggos,可以免去我们编译整个项目的麻烦,特别是我们刚开始的时候想快速体验eggos的功能的时候。
eggos在每个版本会生成一个ISO镜像文件,我们可以从github的release界面直接下载,从网址 https://github.com/icexin/eggos/releases 进入到eggos的release界面,点击eggos.iso下载。







回到Ubuntu,我们需要用到wget远程下载,tar压缩工具下载。
apt-get install wget apt install tar
   远程下载

  • wget命令学习可以看这篇


wget -c -b  https://github.com/icexin/eggos/releases/download/v0.4.1/eggos_0.4.1_Linux_x86_64.tar.gz


安装qemu虚拟机

ubuntu的用户可以通过命令 sudo apt install qemu-system-x86 来安装qemu虚拟机。
apt install qemu-system-x86


启动qemu虚拟机

使用如下命令来启动虚拟机:
qemu-system-x86_64 -m 256M -nographic -no-reboot -serial mon:stdio -netdev user,id=eth0,hostfwd=tcp::8080-:80 -device e1000,netdev=eth0 -cdrom eggos.iso
没有图形界面终端,如windows的wsl需要加上-nographic,从而以非图形化方式启动qemu





  上面的图片表示我们已经安装成功了


体验eggos

  安装好了eggos后,我们就可以来体验下eggos了


JavaScript解释器

我们可以像平常启动node、ipython、jshell那样来使用js
js





⬇️ 接下来我们可以使用js一样来使用这个解释器。
root@eggos# js>>> console.log("this is cub-os github:https://github.com/3293172751")this is cub-os github:https://github.com/3293172751undefined>>> xiongxinwei = new RegExp("xiongxinwei@mail.com")/xiongxinwei@mail.com/    >>> var a = 12, b = 13undefined>>> console.log(a,b)12 13undefined
这个Javascript解释器内置了一个简单的http.Get方法,用于从一个url里面获取内容。
>>> var url = "http://baidu.com">>> resp = http.Get(url)>>> console.log(resp)<html><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></html>
  对上面的解释:
它甚至有自动补全功能,输入http.之后敲击<TAB>键,就可以补全出http.Get。重复按<TAB>可以在多个候选结果间切换。
按<Crtl+D>来退出Javascript解释器。


退出、重新进入

我记录这个板块的原因是文档上并没有给出退出的方法,我尝试了下用Ctrl + Z退出,是成功的,但是后台并没有结束,就和shell下面的Ctrl+C和Ctrl+D的区别⚡
⬇️ 下面我分别开启了8080端口和8081端口,并且企图杀死8080进程并且重新进去





再一次进入
⚠️ 注意,如果你并没有添加qemu-system-x86_64到环境变量,那么我想你必须要去eggos目录下执行。
qemu-system-x86_64 -m 256M -nographic -no-reboot -serial mon:stdio -netdev user,id=eth0,hostfwd=tcp::8080-:80 -device e1000,netdev=eth0 -cdrom eggos.iso


文件系统

eggos现在没有实现完整的文件系统,而是使用了 afero作为文件系统的抽象接口。
afero是一个Go 的文件系统抽象系统。


  • afero翻译和笔记
  • samba协议介绍


⬇️ 我们通过mount命令挂载一个samba文件系统来体验eggos的文件系统功能。
镜像中设置samba文件系统root-1234:





查看自己的IP地址





简单的一个案例如下:
# 找到自己的ipmount smb://root:1234@172.17.0.3:445/samba /share
⚠️ 注意, 这里可能会遇到如下问题


  • 挂载时报错permission denied ,此时是因为这里的用户名也就是上述的icexin的权限不足,可以改为root,或者给权限。
mkdir /home/share && chmod 777 -R /home/share/


  • root@eggos# mount smb://root:1234@172.17.0.3:445/samba /share response error: {Network Name Not Found} The specified share name cannot be found on the remote server. 表示在远程找不到共享名称

第一个好像配置的有问题,但是不知道什么原因,所以又配置了一个samba1,这个成功了







root@eggos# cd /shareroot@eggos# ls-rw-rw-rw- 111 fib.jsroot@eggos# cat fib.jsfunction fib(n) {        if (n == 1 || n == 2) {                return 1;        }        return fib(n-1) + fib(n-2);}console.log(fib(10))root@eggos# js fib.js55
  对上面的解释:
首先我们通过mount命令将一个samba地址挂载到了本地的一个目录

  • mount的第一个参数是源地址URI,第二个参数是本地的挂载点,这里是/share
  • 源地址URI符合标准的URI格式,其中smb代表我们使用的是samba协议
  • icexin和eggos分别是samba的账号和密码,读者需要替换成自己的账号和密码
  • 172.28.90.3:445为samba服务器的ip和端口,读者需要替换成自己的ip和端口
接着我们使用cd和ls命令切换到/share目录,并列出目录下的文件,目录下有一个fib.js。
然后我们使用cat命令打印出fib.js文件的内容,里面使用Javascript实现了斐波那契数列算法,并打印出第10个斐波那契数。
最后我们执行js命令,用fib.js作为参数,效果是执行了fib.js里面的Javascript代码,打印出结果55。


验证

在docker的ubuntu镜像中创建文件a.c





#include<stdio.h>int mian(){        return 0;}


回到eggos检验:







HTTP服务

eggos内置了一个简单的http服务器,使用go httpd命令即可后台启动HTTP服务器。 这个服务器默认绑定了两个地址:

  • /debug/pprof,go著名的pprof地址,里面可以查看很多当前go进程的debug信息
  • /fs/,根目录的映射,可以从浏览器访问整个文件系统。
打开浏览器,输入http://127.0.0.1:8080/debug/pprof/,即可打开debug页面,从里面我们可以获取当前运行的goroutine堆栈快照。





输入http://127.0.0.1:8080/fs/即可访问文件系统根目录,从里面我们可以发现刚刚挂载的/share目录。





一路点进去之后我们就能访问/share/fib.js的内容。
很遗憾的是目前httpd一旦启动就没办法停止,只能重新启动eggos来停止服务
docker搭建的镜像面临的问题:


docker网络的几种模式


  • bridge模式:使用--network bridge指定,默认使用docker0
  • host模式:使用--network host指定
  • none模式:使用--network none指定
  • container模式:使用--network container:NAME或者容器ID指定


⚠️ 我们需要改成host主机模式访问,或者如果有大佬如果会iptables,直接加iptables转发~,欢迎pr
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
docker run -it --network host --name cubos_host db168e4fe87d


⚡ 我们重新挂载然后访问





⚠️暂时没办法访问,跳过~


NES模拟器

本小节必须在图形界面下运行qemu
eggos内置了一个nes模拟器,也就是我们小时候玩的小霸王游戏机模拟器,可以运行一些简单的任天堂FC游戏。
root@docker-desktop:/home/samba# git clone https://github.com/fogleman/nes.git
接着文件系统那一节的内容,我们这次需要在共享文件夹里面准备一个nes rom。
root@eggos#  mount smb://root:1234@172.17.0.3:445/samba /share2root@eggos# ls /share2-rw-rw-rw- 111   fib.js-rw-rw-rw- 40976 mario.nes
相比于之前,多了一个mario.nes文件,这个就是我们即将运行的超级马里奥兄弟游戏。
执行如下命令即可启动nes模拟器,其中-rom参数指定待运行的rom文件。
root@eggos# nes -rom /share/mario.nes
如果一切成功的话,可以看到如下画面





操作按键是固定的,分别如下:

  • W, S, A, D控制手柄的上下左右
  • K, J控制手柄的A和B
  • 空格和回车控制手柄的选择和开始
  • Q键可以退出游戏
如果不开启模拟器加速的话,运行会比较卡,MacOS用户可以通过在启动qemu的时候添加-M accel=hvf开启硬件加速,linux用户可以添加-M accel=kvm来启动加速。


镜像



<hr>

到这里就构建出第二版镜像文件了
docker pull 3293172751/cubos-ubuntu:1.0.5


扩展阅读


  • [1] A JavaScript interpreter in Go https://github.com/robertkrimen/otto
  • [2] Ubuntu上安装samba服务 https://ubuntu.com/tutorials/install-and-configure-samba
  • [3] NES emulator written in Go https://github.com/fogleman/nes
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表