黑胶唱片Rails,能抗能打

今天在Hacker New上看到了一篇称赞Raisl的文章Why Rails Still Matters。 原文用黑胶唱片做为引子,说明以rails为代表的老旧web技术是ok的,不比 新的Next.js之类差很多,大家的应用场景不同而已. 个人顾个人的场子,井水不犯河水就好. 我的想法 我是从Rails入行的软件开发,入职了在一个很小的微型企业. 从Rails开始,我慢慢接触并且使用了Vim, Linux, Ruby, ORM, SQL, Postgresql, Python(在大学只是理论学习), Lua, Javascript, CSS, Markdown, Docker, Go, Kubernetes, Rust等等各种各样的技术. 可以说Rails是我从事IT行业的引路人. 最后从事和Ruby相关的工作是2016年的时候,负责给一个稍微大一点的 初创公司运维那些web服务器,数据库之类的. 时间过得很快,我很久没接触Rails或者Ruby了. 记不清是哪一个时间段,我非常喜欢静态强类型的编程语言. 估计是被Ruby的 method call chian链路搞烦了,也可能是被class搞烦了. 现在我也不喜欢Python的class 和所有的oop编程语言(java为代表, C++也不喜欢). web/http 整个web开发说白了基本上是面向浏览器开发,包含前后端技术. 前端不多多说,html/css/javascript三个加起来本质上就是浏览器的DSL. 最新的wasm稍微可以说自己脱离了浏览器的控制,但也没脱离多少. Node.js/deno也不敢完全说自己和浏览器没少关系 后端方面,屁股决定脑袋,也受到了浏览器不小的制约,看看Nginx和Header相关配置有多少就知道我在说什么了. HTTP协议这么多年了,也是受到浏览器的控制的,毕竟协议谁都可以写. 市场支持不支持,支持的多不多,是和协议本身的各项指标关系不大的. 浏览器本身是一个很复杂而软件,复杂程度不输操作系统. 越是靠近用户层就越复杂,因为用户/人类是变数最多的. 相反,越靠近物理硬件,软件就可以设计的越简单. 比如网络传输的物理层,网络层,传输层,是一层复杂过一层,一层包一层, 像俄罗斯套娃一样. 操作系统,管好4大件,处理好中断,调度就好了. 浏览器光是html的渲染(想象一下一个动态的window size)就够复杂了, 别提那些音/视频API、网络请求、安全策略了 Gemini 最后用gemini总结一下这篇文章,并介绍一下Rails和Next.js的背景,以及现在的web开发趋势。 我基本认同gmini的说法。 文章主要思想 这篇文章的核心观点是,虽然像Next.js这样的新兴前端框架提供了更高级的功能和更精美的界面,但Ruby on Rails仍然是一个有价值的web开发工具,尤其是在注重简单性、开发速度和可维护性的项目上。作者认为,现代JavaScript框架的复杂性实际上会增加开发难度,而Rails的抽象和对web基础的关注使其成为许多应用程序的强大选择,即使在AI和动态web体验的时代也是如此。他用黑胶唱片类比,说明了为什么旧技术在新的创新出现后仍然存在并有价值。本质上,这篇文章推崇Rails是一种实用、高效且具有成本效益的解决方案,即使它不是“最新潮”的技术。 Rails 和 Next.js 的背景 Ruby on Rails (Rails):是一个基于Ruby语言的web应用开发框架。它由David Heinemeier Hansson于2003年创建,旨在提高开发效率和简化web应用开发过程。Rails遵循“约定优于配置”的原则,提供了一系列工具和约定,帮助开发者快速构建功能丰富的web应用。它在过去二十年中一直是流行的后端框架,许多知名公司如Airbnb、Shopify、Github等都使用Rails构建。 ...

February 22, 2025 · datewu

nopCloser函数

update: ioutil逐渐被io 取代。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package ioutil // import "io/ioutil" func NopCloser(r io.Reader) io.ReadCloser NopCloser returns a ReadCloser with a no-op Close method wrapping the provided Reader r. As of Go 1.16, this function simply calls io.NopCloser. package io // import "io" func NopCloser(r Reader) ReadCloser NopCloser returns a ReadCloser with a no-op Close method wrapping the provided Reader r. 最近使用baloo写集成测试,遇到了个需求, 在unmarshalrespones之后(或者之前)还要再输出一次response的纯文本格式供debug参考。 即需要多次读http.Resp.Body。 问题 response.Body 只能读一次,读完之后再进行read操作就会遇到EOF error。 分析问题 模糊记得baloo在一次请求中能多次(JSON() 和 String())读取response.Body内容。 仔细去看了下baloo的源代码,发现baloo自己在内部 封装了一个对象 http.RawResonse ,使用了 iouti.NopCloser函数重新填充了res.Body: 1 2 3 4 5 6 7 8 9 10 func readBodyJSON(res *http.Response) ([]byte, error) { body, err := ioutil.ReadAll(res.Body) if err != nil { return []byte{}, err } // Re-fill body reader stream after reading it res.Body = ioutil.NopCloser(bytes.NewBuffer(body)) return body, err } 解决方案 有了 ioutil.NopCloser函数,可以很快速的写出debugPlugin: ...

April 17, 2019 · datewu

配置http selinux

今天在digitocean一台新申请的主机上部署web应用。部署完成,打开浏览器发现报错403。 部署的web应用很简单,后端用nginx做了反向代理,应该没啥大问题。 进一步打开chrome的console,发现对static file的访问报错403,还没到后端就已经报错了, 估计后面的 upstream socket也会报错。 ssh登陆到服务器上看了下nginx的日志,发现是权限的问题。 进一步debug了之后发现虚拟机开启selinux,当时心头就一紧,估计要改selinux配置了,这是个麻烦事儿。 想简单点直接关闭selinux,转念一想digitocean的主机直接暴露在interner上,开着selinux 其实是个很好的保护。digitocean打开自有它打开的道理,我猜可能有很多vm被攻破沦为僵尸网络了。 google搜索了selinux的web server常用的配置,验证后,解决了nginx 403的问题。记录分享如下: check seLinux 查看系统状态 查看selinux配置和状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 [root@deo ~]# sestatus -v SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Max kernel policy version: 28 Process contexts: Current context: unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 Init context: system_u:system_r:init_t:s0 /usr/sbin/sshd system_u:system_r:sshd_t:s0-s0:c0.c1023 File contexts: Controlling terminal: unconfined_u:object_r:user_devpts_t:s0 /etc/passwd system_u:object_r:passwd_file_t:s0 /etc/shadow system_u:object_r:shadow_t:s0 /bin/bash system_u:object_r:shell_exec_t:s0 /bin/login system_u:object_r:login_exec_t:s0 /bin/sh system_u:object_r:bin_t:s0 -> system_u:object_r:shell_exec_t:s0 /sbin/agetty system_u:object_r:getty_exec_t:s0 /sbin/init system_u:object_r:bin_t:s0 -> system_u:object_r:init_exec_t:s0 /usr/sbin/sshd system_u:object_r:sshd_exec_t:s0 查看文件目录的selinux label 1 2 3 4 5 6 [root@deo ]# ls -Z /opt/todolist -rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 index.html drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 static [root@deo ]# ls -Z /usr/share/nginx/html -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 50x.html -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html meat 下面两种方法选一种就可以了 ...

April 16, 2018 · datewu