标签归档:xishui

HTTP状态码大全

发现网上中文的HTTP状态码都不够完整,于是整理一个比较完整的。

HTTP 状态码 1xx消息

这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。由于HTTP/1.0协议中没有定义任何1xx状态码,所以除非在某些试验条件下,服务器禁止向此类客户端发送1xx响应。 这些状态码代表的响应都是信息性的,标示客户应该采取的其他行动。

  • 100 Continue
    服务器已经接收到请求头,并且客户端应继续发送请求主体(在需要发送身体的请求的情况下:例如,POST请求),或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。要使服务器检查请求的头部,客户端必须在其初始请求中发送Expect: 100-continue作为头部,并在发送正文之前接收100 Continue状态代码。响应代码417期望失败表示请求不应继续。
  • 101 Switching Protocols
    服务器已经理解了客户端的请求,并将通过Upgrade消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到在Upgrade消息头中定义的那些协议。
    只有在切换新的协议更有好处的时候才应该采取类似措施。例如,切换到新的HTTP版本(如HTTP/2)比旧版本更有优势,或者切换到一个实时且同步的协议(如WebSocket)以传送利用此类特性的资源。
  • 102 Processing(WebDAV;RFC 2518)
    WebDAV请求可能包含许多涉及文件操作的子请求,需要很长时间才能完成请求。该代码表示​​服务器已经收到并正在处理请求,但无响应可用。这样可以防止客户端超时,并假设请求丢失。

HTTP 状态码 2xx成功

这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。

  • 200 OK
    请求已成功,请求所希望的响应头或数据体将随此响应返回。实际的响应将取决于所使用的请求方法。在GET请求中,响应将包含与请求的资源相对应的实体。在POST请求中,响应将包含描述或操作结果的实体。
  • 201 Created
    请求已经被实现,而且有一个新的资源已经依据请求的需要而创建,且其URI已经随Location头信息返回。假如需要的资源无法及时创建的话,应当返回’202 Accepted’。
  • 202 Accepted
    服务器已接受请求,但尚未处理。最终该请求可能会也可能不会被执行,并且可能在处理发生时被禁止。
  • 203 Non-Authoritative Information(自HTTP / 1.1起)
    服务器是一个转换代理服务器(transforming proxy,例如网络加速器),以200 OK状态码为起源,但回应了原始响应的修改版本。
  • 204 No Content
    服务器成功处理了请求,没有返回任何内容。
  • 205 Reset Content
    服务器成功处理了请求,但没有返回任何内容。与204响应不同,此响应要求请求者重置文档视图。
  • 206 Partial Content(RFC 7233)
    服务器已经成功处理了部分GET请求。类似于FlashGet或者迅雷这类的HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。
  • 207 Multi-Status(WebDAV;RFC 4918)
    代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。
  • 208 Already Reported (WebDAV;RFC 5842)
    DAV绑定的成员已经在(多状态)响应之前的部分被列举,且未被再次包含。
  • 226 IM Used (RFC 3229)
    服务器已经满足了对资源的请求,对实体请求的一个或多个实体操作的结果表示。

HTTP 状态码 3xx重定向

这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的Location域中指明。

当且仅当后续的请求所使用的方法是GET或者HEAD时,用户浏览器才可以在没有用户介入的情况下自动提交所需要的后续请求。客户端应当自动监测无限循环重定向(例如:A→B→C→……→A或A→A),因为这会导致服务器和客户端大量不必要的资源消耗。按照HTTP/1.0版规范的建议,浏览器不应自动访问超过5次的重定向。

  • 300 Multiple Choices
    被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
    除非这是一个HEAD请求,否则该响应应当包括一个资源特性及地址的列表的实体,以便用户或浏览器从中选择最合适的重定向地址。这个实体的格式由Content-Type定义的格式所决定。浏览器可能根据响应的格式以及浏览器自身能力,自动作出最合适的选择。当然,RFC 2616规范并没有规定这样的自动选择该如何进行。
    如果服务器本身已经有了首选的回馈选择,那么在Location中应当指明这个回馈的URI;浏览器可能会将这个Location值作为自动重定向的地址。此外,除非额外指定,否则这个响应也是可缓存的。
  • 301 Moved Permanently
    被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。
    新的永久性的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
    如果这不是一个GET或者HEAD请求,因此浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
    注意:对于某些使用HTTP/1.0协议的浏览器,当它们发送的POST请求得到了一个301响应的话,接下来的重定向请求将会变成GET方式。
  • 302 Found
    要求客户端执行临时重定向(原始描述短语为“Moved Temporarily”)。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
    新的临时性的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
    如果这不是一个GET或者HEAD请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
    注意:虽然RFC 1945和RFC 2068规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将302响应视作为303响应,并且使用GET方式访问在Location中规定的URI,而无视原先请求的方法。因此状态码303和307被添加了进来,用以明确服务器期待客户端进行何种反应。
  • 303 See Other
    对应当前请求的响应可以在另一个URI上被找到,当响应于POST(或PUT / DELETE)接收到响应时,客户端应该假定服务器已经收到数据,并且应该使用单独的GET消息发出重定向。这个方法的存在主要是为了允许由脚本激活的POST请求输出重定向到一个新的资源。这个新的URI不是原始资源的替代引用。同时,303响应禁止被缓存。当然,第二个请求(重定向)可能被缓存。
    新的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
    注意:许多HTTP/1.1版以前的浏览器不能正确理解303状态。如果需要考虑与这些浏览器之间的互动,302状态码应该可以胜任,因为大多数的浏览器处理302响应时的方式恰恰就是上述规范要求客户端处理303响应时应当做的。
  • 304 Not Modified
    表示资源未被修改,因为请求头指定的版本If-Modified-Since或If-None-Match。在这种情况下,由于客户端仍然具有以前下载的副本,因此不需要重新传输资源。
  • 305 Use Proxy
    被请求的资源必须通过指定的代理才能被访问。Location域中将给出指定的代理所在的URI信息,接收者需要重复发送一个单独的请求,通过这个代理才能访问相应资源。只有原始服务器才能创建305响应。许多HTTP客户端(像是Mozilla和Internet Explorer)都没有正确处理这种状态代码的响应,主要是出于安全考虑。
    注意:RFC 2068中没有明确305响应是为了重定向一个单独的请求,而且只能被原始服务器建立。忽视这些限制可能导致严重的安全后果。
  • 306 Switch Proxy
    在最新版的规范中,306状态码已经不再被使用。最初是指“后续请求应使用指定的代理”。
  • 307 Temporary Redirect
    在这种情况下,请求应该与另一个URI重复,但后续的请求应仍使用原始的URI。302相反,当重新发出原始请求时,不允许更改请求方法。 例如,应该使用另一个POST请求来重复POST请求。
  • 308 Permanent Redirect (RFC 7538)
    请求和所有将来的请求应该使用另一个URI重复。 307和308重复302和301的行为,但不允许HTTP方法更改。 例如,将表单提交给永久重定向的资源可能会顺利进行。

HTTP 状态码 4xx客户端错误

这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。除非响应的是一个HEAD请求,否则服务器就应该返回一个解释当前错误状况的实体,以及这是临时的还是永久性的状况。这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误响应中的实体内容。

如果错误发生时客户端正在传送数据,那么使用TCP的服务器实现应当仔细确保在关闭客户端与服务器之间的连接之前,客户端已经收到了包含错误信息的数据包。如果客户端在收到错误信息后继续向服务器发送数据,服务器的TCP栈将向客户端发送一个重置数据包,以清除该客户端所有还未识别的输入缓冲,以免这些数据被服务器上的应用程序读取并干扰后者。

  • 400 Bad Request
    由于明显的客户端错误(例如,格式错误的请求语法,太大的大小,无效的请求消息或欺骗性路由请求),服务器不能或不会处理该请求。
  • 401 Unauthorized(RFC 7235)
    类似于403 Forbidden,401语义即“未认证”,即用户没有必要的凭据。该状态码表示当前请求需要用户验证。该响应必须包含一个适用于被请求资源的WWW-Authenticate信息头用以询问用户信息。客户端可以重复提交一个包含恰当的Authorization头信息的请求。如果当前请求已经包含了Authorization证书,那么401响应代表着服务器验证已经拒绝了那些证书。如果401响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息。
    注意:当网站(通常是网站域名)禁止IP地址时,有些网站状态码显示的401,表示该特定地址被拒绝访问网站。
  • 402 Payment Required
    该状态码是为了将来可能的需求而预留的。该状态码最初的意图可能被用作某种形式的数字现金或在线支付方案的一部分,但几乎没有哪家服务商使用,而且这个状态码通常不被使用。如果特定开发人员已超过请求的每日限制,Google Developers API会使用此状态码。
  • 403 Forbidden
    服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个HEAD请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个404响应,假如它不希望让客户端获得任何信息。
  • 404 Not Found
    请求失败,请求所希望得到的资源未被在服务器上发现,但允许用户的后续请求。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。
  • 405 Method Not Allowed
    请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow头信息用以表示出当前资源能够接受的请求方法的列表。例如,需要通过POST呈现数据的表单上的GET请求,或只读资源上的PUT请求。
    鉴于PUT,DELETE方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回405错误。
  • 406 Not Acceptable
    请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体,该请求不可接受。
    除非这是一个HEAD请求,否则该响应就应当返回一个包含可以让用户或者浏览器从中选择最合适的实体特性以及地址列表的实体。实体的格式由Content-Type头中定义的媒体类型决定。浏览器可以根据格式及自身能力自行作出最佳选择。但是,规范中并没有定义任何作出此类自动选择的标准。
  • 407 Proxy Authentication Required(RFC 2617)
    与401响应类似,只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个Proxy-Authenticate用以进行身份询问。客户端可以返回一个Proxy-Authorization信息头用以验证。
  • 408 Request Timeout
    请求超时。根据HTTP规范,客户端没有在服务器预备等待的时间内完成一个请求的发送,客户端可以随时再次提交这一请求而无需进行任何更改。
  • 409 Conflict
    表示因为请求存在冲突无法处理该请求,例如多个同步更新之间的编辑冲突。
  • 410 Gone
    表示所请求的资源不再可用,将不再可用。当资源被有意地删除并且资源应被清除时,应该使用这个。在收到410状态码后,用户应停止再次请求资源。但大多数服务端不会使用此状态码,而是直接使用404状态码。
  • 411 Length Required
    服务器拒绝在没有定义Content-Length头的情况下接受请求。在添加了表明请求消息体长度的有效Content-Length头之后,客户端可以再次提交该请求。
  • 412 Precondition Failed(RFC 7232)
    服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。
  • 413 Request Entity Too Large(RFC 7231)
    前称“Request Entity Too Large”,表示服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。
    如果这个状况是临时的,服务器应当返回一个Retry-After的响应头,以告知客户端可以在多少时间以后重新尝试。
  • 414 Request-URI Too Long(RFC 7231)
    前称“Request-URI Too Long”,表示请求的URI长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。通常将太多数据的结果编码为GET请求的查询字符串,在这种情况下,应将其转换为POST请求。这比较少见,通常的情况包括:

    • 本应使用POST方法的表单提交变成了GET方法,导致查询字符串过长。
    • 重定向URI“黑洞”,例如每次重定向把旧的URI作为新的URI的一部分,导致在若干次重定向后URI超长。
    • 客户端正在尝试利用某些服务器中存在的安全漏洞攻击服务器。这类服务器使用固定长度的缓冲读取或操作请求的URI,当GET后的参数超过某个数值后,可能会产生缓冲区溢出,导致任意代码被执行。没有此类漏洞的服务器,应当返回414状态码。
  • 415 Unsupported Media Type
    对于当前请求的方法和所请求的资源,请求中提交的互联网媒体类型并不是服务器中所支持的格式,因此请求被拒绝。例如,客户端将图像上传格式为svg,但服务器要求图像使用上传格式为jpg。
  • 416 Requested Range Not Satisfiable(RFC 7233)
    前称“Requested Range Not Satisfiable”。客户端已经要求文件的一部分(Byte serving),但服务器不能提供该部分。例如,如果客户端要求文件的一部分超出文件尾端。
  • 417 Expectation Failed
    在请求头Expect中指定的预期内容无法被服务器满足,或者这个服务器是一个代理服显的证据证明在当前路由的下一个节点上,Expect的内容无法被满足。
  • 418 I’m a teapot(RFC 2324)
    本操作码是在1998年作为IETF的传统愚人节笑话, 在RFC 2324超文本咖啡壶控制协议’中定义的,并不需要在真实的HTTP服务器中定义。当一个控制茶壶的HTCPCP收到BREW或POST指令要求其煮咖啡时应当回传此错误。这个HTTP状态码在某些网站(包括Google.com)中用作彩蛋。
  • 421 Misdirected Request (RFC 7540)
    该请求针对的是无法产生响应的服务器(例如因为连接重用)。
  • 422 Unprocessable Entity(WebDAV;RFC 4918 )
    请求格式正确,但是由于含有语义错误,无法响应。
  • 423 Locked(WebDAV;RFC 4918)
    当前资源被锁定。
  • 424 Failed Dependency(WebDAV;RFC 4918)
    由于之前的某个请求发生的错误,导致当前请求失败,例如PROPPATCH。
  • 426 Upgrade Required(RFC 2817)
    客户端应当切换到TLS/1.0,并在HTTP/1.1 Upgrade header中给出。
  • 428 Precondition Required (RFC 6585)
    原服务器要求该请求满足一定条件。这是为了防止“‘未更新’问题,即客户端读取(GET)一个资源的状态,更改它,并将它写(PUT)回服务器,但这期间第三方已经在服务器上更改了该资源的状态,因此导致了冲突。”
  • 429 Too Many Requests (RFC 6585)
    用户在给定的时间内发送了太多的请求。旨在用于网络限速。
  • 431 Request Header Fields Too Large (RFC 6585)
    服务器不愿处理请求,因为一个或多个头字段过大。
  • 451 Unavailable For Legal Reasons
    该访问因法律的要求而被拒绝,由IETF在2015核准后新增加。

HTTP 状态码 5xx服务器错误

表示服务器无法完成明显有效的请求。这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。除非这是一个HEAD请求,否则服务器应当包含一个解释当前错误状态以及这个状况是临时的还是永久的解释信息实体。浏览器应当向用户展示任何在当前响应中被包含的实体。这些状态码适用于任何响应方法。

  • 500 Internal Server Error
    通用错误消息,服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。没有给出具体错误信息。
  • 501 Not Implemented
    服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。(例如,网络服务API的新功能)
  • 502 Bad Gateway
    作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
  • 503 Service Unavailable
    由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是暂时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个Retry-After头用以标明这个延迟时间。如果没有给出这个Retry-After信息,那么客户端应当以处理500响应的方式处理它。
  • 504 Gateway Timeout
    作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。
    注意:某些代理服务器在DNS查询超时时会返回400或者500错误。
  • 505 HTTP Version Not Supported
    服务器不支持,或者拒绝支持在请求中使用的HTTP版本。这暗示着服务器不能或不愿使用与客户端相同的版本。响应中应当包含一个描述了为何版本不被支持以及服务器支持哪些协议的实体。
  • 506 Variant Also Negotiates(RFC 2295)
    由《透明内容协商协议》(RFC 2295)扩展,代表服务器存在内部配置错误,被请求的协商变元资源被配置为在透明内容协商中使用自己,因此在一个协商处理中不是一个合适的重点。
  • 507 Insufficient Storage(WebDAV;RFC 4918)
    服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。
  • 508 Loop Detected (WebDAV;RFC 5842)
    服务器在处理请求时陷入死循环。 (可代替 208状态码)
  • 510 Not Extended(RFC 2774)
    获取资源所需要的策略并没有被满足。
  • 511 Network Authentication Required (RFC 6585)
    客户端需要进行身份验证才能获得网络访问权限,旨在限制用户群访问特定网络。(例如连接WiFi热点时的强制网络门户)

贫富差距的产生

今天看到一个有趣的问题,

想象着,有一个房间,里面有 100 个人,每个人有 100 美元。每过一会,每个有钱的人给随机的其他人 1 美元,经过一段时间后,房间内的资金分配情况是怎样?

粗想想,每个人都是“相同的概率”丢失和获得一元钱,那么大家的资金应该大差不差才是,可惜后面的结果大打脸,贫富差距居然那么明显,实在是非常的反直觉,于是我用JS写了个模拟程序跑跑看。

地址在 https://jsfiddle.net/chxw4kLs/ ,使用Vue来显示图形化的效果,红色的柱状图是0~99号的资金情况,半透明的蓝色是排序后的结果,方便查看。下面文字是最富,最穷,以及首富的变动情况。

结果真的非常出人意料,跑了一段时间后,最富的人已然拥有700多美元,而贫穷的人早已是0元家当。

代码用了一些ES6的东西,可能要比较新的浏览器才能查看效果,Vue真的很好使,这样的一个界面虽然不复杂,但是写的还是挺舒服的。

为什么有人富有人穷呢,即便实在这样一种“公平”的环境下,还是产生了如此悬殊的贫富差距,这就是命运吗?而我们的社会其实并没有那么公平,所以…… 我陷入了深深的沉思😵

焦耳小偷试做

难得偷得半日闲,翻找旧时杂物,坑到一个微型收音机,记得是多年前充话费送的…… 打开自然没有了声响,应该是没电了,于是拆开试了下电路,直接上电还是好的,可惜灵敏度太糟,手不捏天线简直不能用,罢了就丢了。打算丢弃两粒纽扣电池时,突然想到前几日在微信推送里看到的焦耳小偷电路,仅三个元件就能实现升压,把废旧电池里的剩余电量榨取干净,当时看过就算了,现在一琢磨正是绝好的试做机会。

打算丢弃的俩电池,串联后1.5V不到……

焦耳小偷电路也有趣的很,原理图如下,一个磁环上反响绕制的两个线圈,一个通过电阻连晶体管基极,另一个直连集电极,基极线圈通电使集电极导通,集电极导通后产生的磁场又抑制了基极线圈的导通于是再次断开,没有了磁场基极又能导通,如此往复,集电极的线圈上产生了高速的通断现象,这样电感就可以蓄放出比电压更高的电压,点亮一个LED不在话下。

“焦耳小偷”的图片搜索结果

当然上面是理论,我没有磁环也没有合适的漆包线,不过懂了原理后还是可以山寨的,于是我拿了俩陈年电感——

就是这种电感,感觉是早年的产品了,现在基本都是色环电感了

只要俩电感挨近一点,应该也是有这个效果的,只是山寨出效果就行了咱就不追求完美了啊。

确实不太亮,不过也确实亮了

电路面包板上找了个空隙搭的,很是凌乱,就将就看吧。两个过气的纽扣电池一共1.5V是带不动黄色LED的,不过用上这电路后就行了,虽然也很暗(白天,原件用的又很随意,纽扣电池的剩余电量确实也不多了),焦耳小偷当然不可能无中生有,只是更多的从电源提取电流,然后转变为更高的电压提供给负载。

如果我把两个电感距离分开一点,LED亮度就会下降,再远一些就会熄灭,说明两个电感直接确实是互相作用的,还有一开始我基极电阻加的比较大,发现LED无法点亮,我用万用表测量的时候发现一碰到基极就可以量,分析下来应该是电路没有“起振”(词用的不对,但是就是这个意思啦),换用更小的电阻后就能自己亮了。于是继续压榨这俩电池到再也不行为止:)

虽然很有趣,不过这种简单的电路也只能用在点亮个LED的水准上,焦耳小偷电路输出的其实是直流脉冲(电感不断通断),正式的场景应该还需要升压电路来运作。网上似乎有挺高级的分析,若有兴趣也可以研究下。

又水了一篇文章,耶 ( •̀ ω •́ )y

在 Vue 中使用 lodash 的小坑

  1. 虽然lodash的pull是修改原变量,但是不会被Vue捕获的,因为Vue只是劫持了其监视值的相关方法(splice等),而lodash的pull直接使用了Array.propotype.splice,所以,要么使用without后重新复制,要么老老实实用原生的splice来删除。

太久不登录了,密码都试了三次才行……

MobX —— 10分钟极速入门 MobX 与 React

MobX 是一个简单、方便扩展、久经考验的状态管理解决方案。这个教程旨在十分钟内向你介绍 MobX 的一些重要概念。MobX 是一个独立的苦,不过大多数人都把它和 React 一起使用,所以本教程也就着眼于这个组合展开。

核心概念

State 是每一个应用程序的核心部分,而使用一个不合规范的 State 则是让你的应用充满 bug 和失控的不二法门,或者就是局部变量环绕,让你的 state 失去了同步。有很多框架试图解决这个问题,比如使用不可变的 state,但是这样以来又带来了新的问题,比如数据必须规格化,完整性约束失效等等。

MobX 让整个事情又变简单了:它不允许产生失控的 state。它的理念也很简单:所有可以从 state 中派生的事物,都会自动的派生。

把 MobX 想象成 Excel 表格。

  1. 首先,有一个 state,它可以是一个object,array,primitives等等任何组成你程序的部分。你可以把这个想象成你应用程序的“单元格”。
  2. 然后就是 derivations,一般它是指可以从 state 中直接计算的来的结果。比如未完成的任务的数量,这个比较简单,也可以稍复杂一些比如渲染你的任务显示的html。它类似于你的应用程序中的“公式和图表”。
  3. Reactions 和 derivations 很像,主要的区别在于 reactions 并不产生数据结果,而是自动完成一些任务,一般是和 I/O 相关的。他们保证了 DOM 和 网络请求会自动适时地出发。
  4. 最后是 actions。Actions 指的是所有会改变 state 的事情,MobX 保证所有 actions 都会有对应的 derivations 和 reactions 相伴,保证同步。

一个简单的 todo 的 state

理论说的够多的了,看一个例子也许会更明白一些。我们从一个简单的 todo 程序开始。

下面是一个简单直接的 TodoStore,没有鱼丸,没有粗面,没有 MobX ……

我们创建了一个 todoStore,它拥有一个 todos 集合。现在我们往这个 todoStore 里添加一些东西,为了明显起见,我们每修改一个地方,就调用todoStore.report

到现在为止,没有什么特别的。不过如果我们可以不再手动调用 report 方法,事情会不会更美好一些?我们只需要在想要的地方修改这个 state,所有的汇报都自动来做。

太巧了,这就是 MobX 能为你做的事情。自动执行只在 state 改变的时候触发,就好像 Excel 中的图表只在单元格数据改变时更新一样。为了达到这个目标,TodoStore 必须成为可观测的(observable)才行,让我们来改一些代码。

同时,completedTodosCount 属性应该被自动派生,使用 @observable 和 @computed 装饰器来做这些事情:

运行它,太棒了,我们每次赋值都能获得输出结果了。

有个 pendingRequests 暂时没用到,我们后面会用。另外这个教程都用了 ES6 的写法,不过 MobX 也支持 ES5 的写法。

在这个构造器中,我们使用autorun包裹了一个打出report的小函数。Autorun里的东西首先会运行一次,然后当其中的函数有observable的数据发生变化时,会再次运行。 这里我们使用了todos属性,每次todos变化了我们就打印出新的东西。

(可以自己试试结果)

非常有趣是吧,report确实自己执行了,而且同步又精准。如果你仔细查看运行结果的话,你挥发性我们的第四句语句没有产生输出,因为我们修改了todos[1]的数据,而我们在report中指明的数据,并没有todos[1]的变化而发生变化。而第五句话修改了todos[0]的数据则输出了。这个例子很好的说明了,autorun不是简单的监视了todos,而是精确到了具体的一项。

让React更美好

好了,到目前未知,我们使report自动化了,是实话把react拉出来遛遛了。为了是的react 的组件可以识别mobx,我们需要使用mobx-react包来完成,使用autorun,自动的让组件和state同步,这个简直就和上面的让report自动输出一样简单。

下面是一个react 组件,唯一MobX出场的地方就是一个@observer修饰符,这已经足够了,你再也不用使用setState了,你也不需要指明这个组件需要关注state的哪个部分,也不许手动写什么高阶组件。一般来说,所有的部件都变成人工智能了,即使他被定义成一个木偶(纯展示)组件。

执行下面的语句,我们会发现MobX帮我们把数据的更改反应到界面上去了。

 

使用引用(References)

到现在位置,我们已经使用 observable 创建了个数据类型了。也许你会想,MobX 能不能应付引用呢?在之前的例子里,你可能主意到了又一个 assignee 的属性,我们就在这里放另外的一个 store,然后把它赋值给 tasks。

毫无疑问的,MobX 把着一切打理的井井有条。使用 MobX ,不需要规格话数据,不需要指明控件,事实上你的数据在哪里都无所谓。只要 observale 了,什么都好了。

 

 

总结

好了,仅仅依靠一些简单的修饰器,我们就让 react 程序如此生动有趣。最后总结一些:

@observale 修饰器或者 observable 函数让对象可以被追踪;
@computed 修饰器创造了自动运算的表达式;
autorun 函数让依靠 observable 的函数自动执行,这个用来写 log,发请求很不错;
@observer 修饰器让 React 组建自动起来,它会自动更新,即便是在一个很大的程序里也会工作的很好;

最后,MobX 不是一个状态容器

很多人把 MobX 当作另外一个 Redux,但是它仅仅是一个库,不是一个什么架构。上面的例子还是需要程序员自己去组织逻辑和store或者控制器什么的,正如有人在 HackerNews 上所说的:

 

“MobX, it’s been mentioned elsewhere but I can’t help but sing its praises. Writing in MobX means that using controllers/ dispatchers/ actions/ supervisors or another form of managing dataflow returns to being an architectural concern you can pattern to your application’s needs, rather than being something that’s required by default for anything more than a Todo app.”

父亲节的碎碎念

自打换了工作,有了娃儿,博客又荒了。要说真挤不出一丁点时间来耕作,应该还不至于,但是总感觉精力不够,每天八九点多就昏昏欲睡,早上五六点就要起来,像我这种每晚都要睡足8小时,否则第二天就会假死状态的人,超级羡慕那些拥有“少睡基因”的家伙。

今天是父亲节,算起来是我成为父亲后的第一个父亲节啊,不过,也是我失去父亲后的第一个父亲节……

……多感慨也无益,随便唠叨点别的吧。

昨天不是6.18粉丝节么,趁着各种部件打折的势头,给老婆的笔记本+内存换SSD(就在我打下这句话的时候,顺丰到了,果然迅速)。本来也要给自己的六七年的老电脑更新换代的,B150 + i5 6500,16G DDR4,也换个SSD,买下来3000不到一点点,应该有质的飞跃,但是后来想想自己开PC时间太少了,又基本不玩游戏,何必呢……付款后还是退了款(根本原因还是因为穷吧?),就给老婆的笔记本升升级吧,她照顾孩子比我辛苦多了。

抱歉,我还是不可避免的想起彼岸的父亲,现在辛苦着的母亲,“生活从来不易,当你觉得容易时,是有人为你承担了那份不容易”,我不觉得生活容易,但也没有觉得艰辛,终究是因为自己依靠双亲太多了。

在知乎上看到有人说“父母没有经过你的同意就将你带到这个世界,所以他们必须抚养你,这个必然,孝道和赡养只有人类如此,并不是自然法则,不需要去遵守”,我无从辩驳,而且根本就不想去反驳。生而为人,我幸,艰辛多舛,我命。但有人能在我稚嫩的时候帮我开疆辟土,为我挡风遮雨,即便我长大之后行走的不是康庄大道,但我毕竟站在这里,我有前瞻的无限将来,有回首的美好回忆,此时、此刻,我在想着你们。

换了份工作

5月重新换了份工作,相对来说要严格的多,晚上回家还要陪宝宝玩儿,时间真是少少的,也就想不到更新博客了……又要荒了

2016说是VR元年,很多设备啊游戏啊视频啊AV啊(好像混入了什么不得了的东西)层出不穷,想着前两年挺热的刀剑神域动漫,也算是VR的高端成就,会有一天变成那样吗?有生之年我能看到不~不过想体验还是太不容易了,设备贵,还要很好的电脑。现在用来码字的这台台式机,应该有六七年了吧,但是自动升级到了Win10后,开机又快,Chrome跑的也很流畅,要是什么时候换个SSD,除了网速不够快,我还有什么追求呢?。。。还是省点奶粉钱吧。

 

不要在微信上用material-ui

微信浏览器已经全面升级Webkit内核了(好样的),所以这篇文章有点不合时宜了,仅留做参考。

—————————–

这里说的 material-ui 是指这个UI框架,并不是说 Google 的 Material Design 设计风格。

自打脱离 Angular 的怀抱拥抱 React 后,我把移动端的前端也都用上了 ReactJS,在前端框架的选择过程中,我瞄上了 material-ui 这个实现了google material 设计的框架,虽然部件并不是很丰富,但是已经可以给我省下很多力气了,Github 上的赞也很多,之前做过一个简单的微信应用,因为很简单,所以用起来没有什么太多的问题。这次开始做一个“比较复杂”的应用,没多想还是上了 material-ui,不想……

微信出了个调试工具,看起来像是用 atom 的同系 electron 君做出来的的,可以比较简单的调试公众号网页。因为是 electron,所以内核应该是webkit无误,在开发整个公众号的时候,我一直在上面调试,最后差不多完成迁移到服务器,用手机打开一看,我·乐·个·趣,这是我做的吗??

小小地总结如下:

微信Android版里用的是X5的核心,传说中2010年的技术,也能算的上是“现代浏览器”了,但是它不认识flex,material-ui中大量使用了flex布局,从AppBar到GridList,可以说flex布局是CSS3布局最让人振奋的一点,但是微信一脸茫然,都给解释成block了。

OK,我知道微信里可以用古老的-webkit-box布局,和flex是同根同源,先不说那反人类的写法,react中style用的是字典,意味着style={{display:”flex”,display:”-webkit-box”}}最终只能保留后者,那么不是android版微信的咋办?用 vendor-prefix 库吧,微信游览器根本就不在人家的支持范围内!

于是只能用 className 写原生的css,有些东西是可以这么来一下的,但是 material-ui 中的 component 包裹的太深啦,我都没法指明哪个div哪个 input…… 在写了无数的hack后,终于先点样子了。不过还有个坑是,如果你用postCSS,其中的cssnano会把box类型的声明给自动去掉,记住将autoprefixer的remove选项关掉,我们自己来注意不写费代码吧。

 

不过 toggle 组件一直无法使用,最后查看源码,发现它是依靠 input type=checkbox 来触发的,OK 其实很常规的写法,iPhone上的微信是可以正常动作的,然而在Android微信中,checkbox的input根本就不能修改大小,意味着整个组件只有那么一米米大的触发空间,正常情况下那么一个硕大的Toggle,用户只有点左上角一丁点大的地方的时候才能切换状态;而当你修改一下toggle的大小的时候,你根本不知道那个透明的input在什么位置…… 你给我滚出来我保证不打死你。

最后不得已,放弃组件本身的onToggle,使用外层的元素的onClick来修改toggle的状态,看起来倒也不错。

 

还有一个我到现在也没明白为啥,dropdown menu 和 select field 在微信里是空白,点开倒是能显示咯菜单背景,但是菜单项看不到,也不可点选,我实在是没力气去debug了,换回原生的select……

 

最后,material-ui本身还是不错的,在手机版chrome上运行良好,就是我大魅族自带浏览器都运行的很正常。只是没想到亿万用户的微信浏览器这么孱弱,之前一直用bootstrap给微信做前端,看来还是有道理的,太激进的技术是要代价滴。希望微信也多多加油,跟上日新月异的前端发展,不要成为移动时代的IE6哇。

60行的fly flappy bird

fly flappy bird现在是一点都不新鲜了,当初热遍全球的时候,还是有好多人在仿制,各种语言都有……除了对技术的兴趣,还有的应该就是“看,我也有水平做出一个火遍世界的游戏,只是没动手罢了”这点小心思吧,(●’◡’●)

记得曾经在网上看过js版本的,用的库也各式各样,按说我这里有很多pygame的教程,用pygame写一个是正统,诚然也不难,但是我现在越来越觉得pygame过于底层,是的,没有精灵,没有动画,没有碰撞,甚至连基本的场景管理也没有,对于理解游戏底层原理挺合适,但是恐怕真的不适合现代化的游戏开发吧。

工作上,我前后端都做,html5和js接触颇多,虽说html5的效率一直被诟病,还还是有很多粉丝对h5的未来充满希望,个人虽然没有那么那么的乐观,但是看到h5能做的事情越来越多,还是很高兴的,尤其是h5开发游戏也慢慢变得实际起来了。

说到h5的游戏引擎,国内最热的应该是cocos2D-html5吧,还有就是原生DOM操作了……但是因为cocos2D用的人太多了,完全没有我们外行插足的余地,所以我选择了一个相对冷门的引擎“Phaser”来完成今天的功课。若问为什么选这个?因为Github上赞数1.2W啊(cocos才2k多的说)!

这次只有60行的版本,并不完整,只有一个游戏中的状态,没有开始和结束,但是只是为了演示,所以就这样吧,要求不能太高。

首先是html的骨架:

其次就是main.js的全部内容了,因为不少注释,看起来挺多,其实有效代码就60行左右。

=======》点击这里试玩 《========

链接一点开,小鸟儿就开始掉落了,请及时按空格拯救它……

啊,我有点控制不住自己又要挖坑的洪荒之力了,要不咱开个Phaser的坑咋样?(其实我也不是那么喜欢挖坑的,真的是有趣的技术太多,自己时间又太少——)

ReactJS小记(3)

我又来标题党了,最近感觉,使用ReactJS都是高手,太基础的东西好像多说也没意思了,今天还是来点(湿嗒嗒的)干货吧!

ES6是JavaScript的未来(其实已经到来了),有了很多新的语法(糖?),给我们编码带来了不少方便,随意还是与时俱进用ES6和Webpack创造新的世界吧。对了顺便说一下,ES2015就是ES6,而ES7应该算ES2016?

ReactJS中Component用ES6的Class应该怎么写呢?

 ES7中更厉害,直接作为属性写就行,不过实在太新了,暂时还是不写了避免混淆。

ES6的Component怎么用Mixin呢?

文档说了,ES6的语法暂时不支持Mixin,不过我们有张良计,虽然麻烦了一点~