关于ruby-on-rails:玩转JUC工具Java并发编程不再危机四伏

前言 当今互联网利用广泛须要反对高并发拜访,而Java作为一种宽泛应用的编程语言,其并发编程能力对于实现高性能的利用十分重要。而Java的JUC(java.util.concurrent)并发工具就提供了许多实用的工具类和接口,能够让Java利用轻松实现高效的并发编程。ReetrantLock ReentrantLock是Java提供的一个可重入锁,也是Java并发编程中最罕用的一种锁。与synchronized关键字相比,ReentrantLock具备更大的灵活性和性能,能够更好地反对并发编程的实现。特点 可重入性:与synchronized一样,ReentrantLock也反对可重入锁,即同一个线程能够反复取得该锁,而不会呈现死锁。偏心锁:ReentrantLock能够创立偏心锁,即依照线程申请的程序调配锁,确保等待时间最长的线程最先取得锁,防止了线程饥饿问题。中断响应:当线程期待获取锁的过程中,能够通过调用interrupt()办法中断期待,防止线程有限期待。条件变量:ReentrantLock能够创立多个Condition对象,用于控制线程期待和唤醒,从而实现更灵便的线程合作。性能优越:在高度竞争的多线程环境中,ReentrantLock相比synchronized有更好的性能体现,特地是在多处理器零碎中。 简略应用模仿秒杀商品场景public class SecKillDemo { private static int stock = 1;// 秒杀锁private static final ReentrantLock lock = new ReentrantLock();public static void main(String[] args) { // 模仿多个用户抢购 for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { // 加锁 lock.lock(); try { // 判断库存是否足够 if (stock > 0) { // 模仿生成订单 System.out.println(Thread.currentThread().getName() + "抢购胜利,生成订单"); // 缩小库存 stock--; } else { System.out.println(Thread.currentThread().getName() + "抢购失败,库存有余"); } } finally { // 解锁 lock.unlock(); } } }).start(); }}}复制代码加锁后果:最先进来的线程抢购胜利其余线程抢购失败 ...

April 4, 2023 · 4 min · jiezi

关于ruby-on-rails:IO阻塞和非阻塞同步和异步

阻塞和非阻塞 阻塞的时候线程会被挂起 阻塞:当数据还没筹备好时,调用了阻塞的办法,则线程会被挂起,会让出CPU工夫片,此时是无奈解决过去的申请,须要期待其余线程来进行唤醒,该线程能力进行后续操作或者解决其余申请。非阻塞:意味着,当数据还没筹备好的时候,即使我调用了阻塞办法,该线程也不会被挂起,后续的申请也可能被解决。同步 同步和异步跟串行和并行十分形似。 假如在一个场景下:实现一个大工作须要4个小工作。同步的做法:须要顺次4个步骤,留神这里是顺次,也就是说实现这个步骤,须要先实现前置步骤,也就是说下一个步骤是要看上一个步骤的执行后果。 异步的做法:能够同时进行4个步骤,无需期待其余步骤的执行后果。 阻塞和同步的最实质差异在于: 即使是同步,在期待的过程中,线程是不会被挂起,也不须要让出CPU工夫片的, 在IO中的体现 网络编程的根本模型是:Client/Server模型 两个过程之间要互相通信,其中服务端须要提供地位信息,让客户端找到本人。服务端提供IP地址和监听的端口。客户端拿着这些信息去向服务端发动建设连贯申请,通过三次握手胜利建设连贯后,客户端就能够通过socket向服务器发送和承受音讯。BIO BIO通信模型采纳的是典型的:一申请一应答通信模型 采纳BIO通信模型的服务端,通常会由一个独立的Acceptor线程负责监听客户端的连贯。他不负责解决申请,他只是起到一个委派工作的作用,当他接管到申请之后,会为每个客户端创立一个新的线程进行链路解决。解决完之后,通过输入流,返回应答给客户端,而后线程被销毁,资源被回收。 该模型的最大问题就是不足弹性伸缩能力,服务端的线程个数和客户端的并发拜访数是1:1的关系。因为线程是Java虚拟机十分贵重的资源,当线程书收缩之后,零碎的性能会随着并发量减少呈反比的趋势降落。而且会有OOM的危险,当没有内存空间创立线程时,就无奈解决客户端申请,最终导致过程宕机或卡死,无奈对外提供服务。最大的问题就是:每当有一个客户端申请接入时,就会创立一个线程来解决申请。为了改良这个一线程一连贯模型,前面又演进出通过: 线程池音讯队列 来实现1个或者多个线程解决N个客户端的模型。 在这里,无论是线程池和音讯队列,都是解决内存空间,线程的问题,并没有实质性地扭转同步阻塞通信实质问题 所以这种优化版本的BIO也被称为是伪异步。伪异步IO 采纳线程池和工作队列能够实现一种:伪异步的IO通信 将客户端的申请封装成一个Task(该工作实现java.lang.Runnable接口),投递到音讯队列中。如果通过线程池保护一堆解决线程,去生产队列中的音讯。处理完毕之后,再去通过客户端就能够了,他的资源是可控的,无论客户端的申请量是多少,也不会发生变化,同样这也是他的毛病之一。建设连贯的accpet办法、读取数据的read办法都是阻塞。 这就意味着,如果有一方解决申请或者发出请求的比较慢,或者是网络传输比较慢,那么都会影响对方。当调用OutputStream的write办法写输入流的时候,它将会被阻塞,直到所有要发送的字节全副写入结束,或者产生异样。在TCP/IP中,当音讯的接管方解决迟缓的时候,因为音讯滑动窗口的存在,那么它的接管窗口就会变小,就是那个TCP window size。如果这里采纳同步阻塞IO,并且write操作被阻塞很久,直到TCP window size 大于0或者产生IO异样了。那么通信对方返回应答工夫过长会引起的级联故障: 线程问题:如果所有的可用线程都被故障服务器阻塞,那么后续所有的IO音讯都将被队列中排队。队列问题:如果队列采纳的是有界队列,队列满了之后那么就会无奈后续解决申请;如果采纳的是无界队列,那么会有OOM危险。 NIO NIO,官网叫法是new IO,因为它绝对于之前出的java.io包是新增的然而之前老的IO库都是阻塞的,New IO类库指标就是为了让Java反对非阻塞IO,所有更多的人称为Non-Block IO 缓冲区Buffer Buffer是一个对象,通常是ByteBuffer类型任何时候操作NIO中的数据,都须要通过缓冲区。 在NIO库里,所有数据操作是用缓冲区解决的。 读取数据时,是间接读到缓冲区中(这里并没有间接读到某个中央,而是都放到缓冲区中)写入数据时,写入到缓冲区 缓冲区本质上是一个数组,通常是一个字节数组ByteBuffer,本身还须要保护读写地位,能够用指针或者偏移量来实现。除了ByteBuffer还有其余根本类型缓冲区: CharBuffer:字符缓冲区ShortBuffer:短整型缓冲区IntBuffer:整形缓冲区LongBuffer:长整型缓冲区DoubleBuffer:双精度缓冲区 通常是用ByteBuffer 通道Channel 网络数据通过Channel读取和写入 Channel通道和Stream流最大的区别在于: Channel的数据流向是双向的Stream的数据流向是单向的 这就意味着:应用Channel,能够同时进行读和写,他是全双工模型。(能够联想到HTTP1.1 HTTP2.0 HTTP3.0 ``websocket)多路复用器Selector Selector是NIO编程的根底 Selector会一直轮询注册在其上的Channel。 如果某个Channel产生读写事件,就代表这个Channel是就绪状态,会被Selector轮询进去。而后依据SelectionKey能够获取就绪Channel的汇合,进行后续IO操作。一个Selector能够轮询多个Channel,JDK是基于epoll代替传统的select,所以不受句柄fd的限度。意味着,一个线程负责Selector的轮询千万个客户端,AIO NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现 通过java.util.concurrent.Future类来示意异步操作的后果。在执行异步操作的时候传入一个java.nio.channels CompletionHandler接口的实现类作为操作实现的回调NIO2.0的异步socket通道是真正的异步非阻塞IO。 同步socket channel:SocketServerChannel异步socket channel:AsynchronousServerSocketChannel 它不须要通过多路复用器(selector)对注册到外面的通过进行轮询操作,就能够实现异步读写。 AIO和NIO最大的区别在于:异步Socket Channel是被动执行对象 NIO须要咱们把channel注册到selector上进行程序扫描、轮询AIO则是通过Future类,实现回调办法:completed、failed ...

February 27, 2023 · 1 min · jiezi

关于ruby-on-rails:为什么很多公司都开始使用Go语言了

写在后面最近和几个小伙伴们在写字节跳动第五届青训营后端组的大作业。靠近尾期了,是时候做一些总结了,那从什么中央开始呢?那就从咱们为什么要抉择Go语言开始吧~ 我的项目地址我的项目文档 越来越多的互联网大厂开始应用Go语言了,譬如腾讯、美团、滴滴、百度、Google、bilibili...还有最后应用Python的字节跳动,甚至曾经全面拥向Go了。这么多国内外名列前茅的公司,都在开始应用它了,它到底有什么劣势呢?这就得谈谈它的一些劣势了。ps:当然了,还有Go-To-Byte的成员,想要学习go语言,并且用它实现青训营的大我的项目呐~Go的一些劣势说起劣势,在某些方面多半是因为它有一些他人没有的个性,或者优化了他人麻烦的中央,相比起来,才会更胜一筹。那咱们来理解一下Go的一些特点吧,但在理解僵硬的特点之前,咱们先来看看其它几种常见的语言:常见的一些语言这里不是比照哟,不是说谁好谁坏,而是小马过河,因人而异~1、C/C++C语言是在1971年的时候,被大神Ken Thompson和Dennis Ritchie创造的,而Go语言的主导开发者之一就是Ken Thompson,所以在很多中央和C语言相似,(比方struct、Printf、&取值符)C/C++也作为很多初学初学的语言,它们都是间接编译为机器码,所以执行效率会更高,并且都不须要执行环境,用户的应用老本会更低,不像很多语言还须要装置所需的环境。也因为这些起因,它们的一次编码或编译只实用于一种平台,对于不同操作系统而言,有时须要批改编码再编译,有时间接从新编译即可。而且对于开发者也"很不敌对",须要本人解决垃圾回收(GC)的问题。编码时,还须要思考,堆上的内存什么时候free、delete?代码会不会造成内存泄露、不平安?2、Java本人作为一个从Java来学习Go的菜鸟,还未正式开发,就感到开发效率会比Java低了(个人感觉,不喜勿喷)~Java是间接编译成字节码(.class),这种编译产物是介于原始编码和机器码的一种两头码。这样的话,Java程序就须要特定的执行环境(JVM)了,执行效率相比会低一些,还可能有虚拟化损失。然而这样也有一个益处就是能够编译一次,多处执行(跨平台)。而且它也是自带GC的。3、JavaScript和Python一样,JS是一种解释型语言,它们不须要编译,解释后即可运行。所以Js也是须要特定的执行环境(浏览器引擎) 的。将其代码放入浏览器后,浏览器须要解析代码,所以也会有虚拟化损失。Js只须要浏览器即可运行,所以它也是跨平台的。再谈Go看完了后面几种常见语言的简略介绍。C/C++性能很高,因为它间接编译为二进制,且没有虚拟化损失,Go感觉还不错;Java的主动垃圾回收机制很好,Go感觉也不错;Js的一次编码能够实用能够实用多种平台,Go感觉好极了;而且Go人造具备高并发的能力,是所有语言无可比及的。那咱们来简略总结一下吧! 自带运行环境Runtime,且毋庸解决GC问题 Go程序的运行环境可厉害了,其实大部分语言都有Runtime的概念,比方Java,它程序的运行环境是JVM,须要独自装置。对于Java程序,如果不通过非凡解决,只能运行在有JMV环境的机器上。而Go程序是自带运行环境的,Go程序的Runtime会作为程序的一部分打包进二进制产物,和用户程序一起运行,也就是说Runtime也是一系列.go代码和汇编代码等,用户能够“间接”调用Runtime的函数(比方make([]int, 2, 6),这样的语法,其实就是去调用Runtime中的makeslice函数)。对于Go程序,简略来说就是不须要装置额定的运行环境,即可运行。除非你须要开发Go的程序。正因为这样,Go程序也毋庸解决GC的问题,全权交由Runtime解决(反正要打包到一起)。 疾速编译,且跨平台 不同于C/C++,对于多个平台,可能须要批改代码后再编译。也不同于Java的一次编码,编译成两头码运行在多个平台的虚拟机上。Go只须要一次编码,就能轻松在多个平台编译成机器码运行。值得一提的就是它这跨平台的能力也是Runtime赋予的,因为Runtime有肯定屏蔽零碎调用的能力。 人造反对高性能高并发,且语法简略、学习曲线平缓 C++解决并发的能力也不弱,但因为C++的编码要求很高,如果不是很幼稚、业余的C++程序员,可能会出很多故障。而Go可能教训不是那么丰富,也能写出性能很好的高并发程序。值得一提的就是它这超强的高并发,也是Runtime赋予的去解决协程调度能力。 丰盛的规范库、欠缺的工具链 对于开发者而言,装置好Golang的环境后,就能用官网的规范库开发很多性能了。比方下图所示的很多罕用包: 而且Go本身就具备丰盛的工具链,(比方:代码格式化、单元测试、基准测试、包治理...) 。。。。。。 很多大厂开始应用Go语言、咱们团队为什么应用GoLang,和这些个性,多少都有一些关系吧~

February 22, 2023 · 1 min · jiezi

关于ruby-on-rails:gitlab-如何进入控制台

应用上面的命令: gitlab-rails console而后轻易玩吧 irb(main):037:0> Feature.enable(:feishu_integration)WARNING: Understand the stability and security risks of enabling in-development features with feature flags.See https://docs.gitlab.com/ee/administration/feature_flags.html#risks-when-enabling-features-still-in-development for more information.=> true

January 2, 2023 · 1 min · jiezi

关于ruby-on-rails:为什么要有refreshToken

当你第一次接触的时候,你有没有一个这样子的纳闷,为什么须要refreshToken这个货色,而不是服务器端给一个期限较长甚至永久性的accessToken呢?抱着这个纳闷我在网上搜查了一番,其实这个accessToken的应用期限有点像咱们生存中的入住酒店,当咱们在入住酒店时,会出示咱们的身份证明来注销获取房卡,此时房卡相当于accessToken,能够拜访对应的房间,当你的房卡过期之后就无奈再开启房门了,此时就须要再到前台更新一下房卡,能力失常进入,这个过程也就相当于refreshToken。accessToken使用率相比refreshToken频繁很多,如果按下面所说如果accessToken给定一个较长的无效工夫,就会呈现不可控的权限泄露危险。应用refreshToken能够进步安全性 用户在拜访网站时,accessToken被盗取了,此时攻击者就能够拿这个accessToke拜访权限以内的性能了。如果accessToken设置一个短暂的有效期2小时,攻击者能应用被盗取的accessToken的工夫最多也就2个小时,除非再通过refreshToken刷新accessToken能力失常拜访。 设置accessToken有效期是永恒的,用户在更改明码之后,之前的accessToken也是无效的 总体来说有了refreshToken能够升高accessToken被盗的危险对于JWT无感刷新TOKEN计划(联合axios)业务需要在用户登录利用后,服务器会返回一组数据,其中就蕴含了accessToken和refreshToken,每个accessToken都有一个固定的有效期,如果携带一个过期的token向服务器申请时,服务器会返回401的状态码来通知用户此token过期了,此时就须要用到登录时返回的refreshToken调用刷新Token的接口(Refresh)来更新下新的token再发送申请即可。话不多说,先上代码工具axios作为最热门的http申请库之一,咱们本篇文章就借助它的谬误响应拦截器来实现token无感刷新性能。具体实现 本次基于axios-bz代码片段封装响应拦截器可间接配置到你的我的项目中应用 ✈️ ✈️ 利用interceptors.response,在业务代码获取到接口数据之前进行状态码401判断以后携带的accessToken是否生效。上面是对于interceptors.response中异样阶段解决内容。当响应码为401时,响应拦截器会走中第二个回调函数onRejected 上面代码分段可能会让大家浏览起来不是很顺畅,我间接把整份代码贴在上面,且每一段代码之间都增加了对应的正文 // 最大重发次数const MAX_ERROR_COUNT = 5;// 以后重发次数let currentCount = 0;// 缓存申请队列const queue: ((t: string) => any)[] = [];// 以后是否刷新状态let isRefresh = false; export default async (error: AxiosError<ResponseDataType>) => { const statusCode = error.response?.status; const clearAuth = () => { console.log('身份过期,请从新登录');window.location.replace('/login');// 清空数据sessionStorage.clear();return Promise.reject(error);}; // 为了节俭多余的代码,这里仅展现解决状态码为401的状况 if (statusCode === 401) { // accessToken生效// 判断本地是否有缓存有refreshTokenconst refreshToken = sessionStorage.get('refresh') ?? null;if (!refreshToken) { clearAuth();}// 提取申请的配置const { config } = error;// 判断是否refresh失败且状态码401,再次进入谬误拦截器if (config.url?.includes('refresh')) {clearAuth();}// 判断以后是否为刷新状态中(避免多个申请导致屡次调refresh接口)if (!isRefresh) { // 设置以后状态为刷新中 isRefresh = true; // 如果重发次数超过,间接退出登录 if (currentCount > MAX_ERROR_COUNT) { clearAuth(); } // 减少重试次数 currentCount += 1; try { const { data: { access }, } = await UserAuthApi.refreshToken(refreshToken); // 申请胜利,缓存新的accessToken sessionStorage.set('token', access); // 重置重发次数 currentCount = 0; // 遍历队列,从新发动申请 queue.forEach((cb) => cb(access)); // 返回申请数据 return ApiInstance.request(error.config); } catch { // 刷新token失败,间接退出登录 console.log('请从新登录'); sessionStorage.clear(); window.location.replace('/login'); return Promise.reject(error); } finally { // 重置状态 isRefresh = false; }} else { // 以后正在尝试刷新token,先返回一个promise阻塞申请并推动申请列表中 return new Promise((resolve) => { // 缓存网络申请,等token刷新后间接执行 queue.push((newToken: string) => { Reflect.set(config.headers!, 'authorization', newToken); // @ts-ignore resolve(ApiInstance.request<ResponseDataType<any>>(config)); }); });}} ...

December 30, 2022 · 1 min · jiezi

关于ruby-on-rails:5种高大上的yml文件读取方式你知道吗

1、Environment在Spring中有一个类Environment,它能够被认为是以后应用程序正在运行的环境,它继承了PropertyResolver接口,因而能够作为一个属性解析器应用。先创立一个yml文件,属性如下:person: name: hydra gender: male age: 18复制代码应用起来也非常简单,间接应用@Autowired就能够注入到要应用的类中,而后调用它的getProperty()办法就能够依据属性名称取出对应的值了。@RestControllerpublic class EnvironmentController { @Autowiredprivate Environment environment;@GetMapping("envTest")private void getEnv(){ System.out.println(environment.getProperty("person.name")); System.out.println(environment.getProperty("person.gender")); Integer autoClose = environment .getProperty("person.age", Integer.class); System.out.println(autoClose); String defaultValue = environment .getProperty("person.other", String.class, "defaultValue"); System.out.println(defaultValue);}}复制代码在下面的例子中能够看到,除了简略的获取外,Environment提供的办法还能够对取出的属性值进行类型转换、以及默认值的设置,调用一下下面的接口,打印后果如下:hydramale18defaultValue复制代码除了获取属性外,还能够用来判断激活的配置文件,咱们先在application.yml中激活pro文件:spring: profiles: active: pro复制代码能够通过acceptsProfiles办法来检测某一个配置文件是否被激活加载,或者通过getActiveProfiles办法拿到所有被激活的配置文件。测试接口:@GetMapping("getActiveEnv")private void getActiveEnv(){ System.out.println(environment.acceptsProfiles("pro"));System.out.println(environment.acceptsProfiles("dev"));String[] activeProfiles = environment.getActiveProfiles();for (String activeProfile : activeProfiles) { System.out.println(activeProfile);}}复制代码打印后果:truefalsepro复制代码2、YamlPropertiesFactoryBean在Spring中还能够应用YamlPropertiesFactoryBean来读取自定义配置的yml文件,而不必再被拘谨于application.yml及其激活的其余配置文件。在应用过程中,只须要通过setResources()办法设置自定义yml配置文件的存储门路,再通过getObject()办法获取Properties对象,后续就能够通过它获取具体的属性,上面看一个例子:@GetMapping("fcTest")public void ymlProFctest(){ YamlPropertiesFactoryBean yamlProFb = new YamlPropertiesFactoryBean();yamlProFb.setResources(new ClassPathResource("application2.yml"));Properties properties = yamlProFb.getObject();System.out.println(properties.get("person2.name"));System.out.println(properties.get("person2.gender"));System.out.println(properties.toString());}复制代码查看运行后果,能够读取指定的application2.yml的内容:susanfemale{person2.age=18, person2.gender=female, person2.name=susan}复制代码然而这样的应用中有一个问题,那就是只有在这个接口的申请中可能取到这个属性的值,如果再写一个接口,不应用YamlPropertiesFactoryBean读取配置文件,即便之前的办法曾经读取过这个yml文件一次了,第二个接口取到的依然还是空值。来对这个过程进行一下测试:@Value("${person2.name:null}")private String name;@Value("${person2.gender:null}")private String gender; @GetMapping("fcTest2")public void ymlProFctest2(){ System.out.println(name);System.out.println(gender);}复制代码先调用一次fcTest接口,再调用fcTest2接口时会打印null值:nullnull复制代码想要解决这个问题也很简略,能够配合PropertySourcesPlaceholderConfigurer应用,它实现了BeanFactoryPostProcessor接口,也就是一个bean工厂后置处理器的实现,能够将配置文件的属性值加载到一个Properties文件中。应用办法如下:@Configurationpublic class PropertyConfig { ...

December 28, 2022 · 2 min · jiezi

关于ruby-on-rails:chatwoot安装

根底环境装置首先确保咱们的yum源可用。 1.git装置.yum -y install git2.rvm装置2.1、装置curlyum -y install curl2.2、装置rvmhttps://www.icode9.com/content-3-1038798.html没有报错,间接执行第四步;如果呈现以下报错请执行,请以此执行以下了,以下两条命令: curl -sSL https://rvm.io/mpapis.asc | gpg2 --import - curl -sSL https://rvm.io/pkuczynski.asc | gpg2 --import - 2.3.再次执行装置命令curl -L get.rvm.io | bash -s stable 2.4、执行命令,呈现8条数据,阐明装置胜利find / -name rvm -print 2.5、更新配置文件source /etc/profile.d/rvm.sh2.6、下载rvm的依赖rvm requirements2.7、查看rvm库中已知的ruby版本rvm list known 2.8、装置须要ruby版本我这边装置的是3.0.2 rvm install 3.0.22.9、应用指定版本的rubyrvm use 3.0.22.10、设置默认版本rvm use 3.0.2 --default2.11、查看ruby版本ruby -v

April 17, 2022 · 1 min · jiezi

关于ruby-on-rails:chatwoot问题

1.客户端定义powered2.开启用户注册性能.env环境:By default, Chatwoot will not allow users to create an account[multi-tenancy] from the login page. However, if you are setting up a public server, you can enable signup using: ENABLE_ACCOUNT_SIGNUP=true

April 1, 2022 · 1 min · jiezi

关于ruby-on-rails:译-一个-Rails-开发者眼中的-Hanami

翻译自:Hanami: Thoughts of a Rails developer - DEV Community 引子我还记得第一次据说 Hanami 框架的时候,是几年前,在 Wroclove.rb 会议的时候。过后并没有真正引起我的关注,那时我刚刚进入 Ruby 世界,正 100% 专一于学习 Rails,我不想在大脑认知上,接管另一个框架的信息。 当初,我曾经应用 Rails 工作了好几年,我有点感到疲乏了,我认为当初是接触全新概念的机会。我想起 wroclove.rb 的谈话,我决定学习 Hanami。我最喜爱的学习形式是边做边学,所以我开始了一个名为 flashcard-genius 的玩具我的项目。这个利用的目标是帮忙我学习意大利语单词,它容许用户创立、共享和记忆多组卡片。 接下来大略两个月的业余时间,我开发了这个原型产品(曾经上线:http://flashcard-genius.com)。它应用了根本的的服务端渲染以及 CRUD 操作,它迫使我学习了各种各样的 Hanami 概念,并克服了多个应用过程中所遇到的阻碍。 在本文,我将与你分享我对于 Hanami 的一些印象。 为什么要应用 Hanami?Hanami 的作者 Luga Guidi,心愿能够去 Rails 化。他的次要愿景是构建一个平安的,功能丰富的 Web 框架,这个框架的构造遵循简洁的架构准则,并依赖于通过实战测试的第三方库,如 Sequel,Rack,以及 dry-rb 这些。 听起来很吸引人,对吧?对我来说,的确如此,特地是因为咱们钟爱的 Rails 经常被批评变得过于简单,以及毁坏了一些最佳实际(例如混合了域和数据层)。 内存使用率也可能是 Hanami 的一个潜在益处。Hanami 可能耗费更少的内存,并且速度更快(甚至五倍)(https://rpanachi.com/2016/03/...)。 我喜爱什么初始化初始化 Hanami 利用非常简单。 开始 页面解释了该如何做: 设置我的项目创立第一个路由,并链接与之匹配的控制器行为,视图和模板筹备根本的测试良好的第一印象对我十分重要,因为能够直观的看到事物的变动,使我有趣味持续理解更简单的概念,来构建我的 app。 Hanami 我的项目是一个 “渺小的”https://guides.hanamirb.org/a... Hanami 能够容许存在多个 App 在一个我的项目中,这有助于我的项目大了之后的解构和拆分。同样的,每个我的项目有本人独立的 “lib” 文件夹。 ...

September 17, 2021 · 1 min · jiezi

关于ruby-on-rails:CSRF-Token

定义CSRF: cross-site request forgery(跨站点申请伪造) 导致的起因这要从Cookie的作用来讲起。咱们晓得HTTP申请是无状态的,然而在理论的web利用中,咱们须要申请是有状态的,比方咱们须要记住登录的状态,不必每一个申请都从新登录。想要实现这样的需要咱们就须要Cookie。 Cookie在服务器端通过Set-Cookie来设置须要存储在Cookie的值,而后存储在客户端(浏览器)。之后在客户端发动的任何指向同一个domain的申请中,都会带上这些Cookie的信息。 那么问题就来了,这里只有是针对同一个domain的申请都会带上cookie,然而并不限度这些申请是从哪里发动的。 咱们来看看上面的场景: 至此,咱们应该对CSRF Token有了一个清晰的理解。 在Rails中怎么避免在Rails中,避免这种攻打的办法,就是在任何非GET的申请中,都要验证一个authenticity token. 这个token对应到每一个session,每次生成session的时候就随机产生一个token,并存储在session中。当向服务器发送申请(非GET)的时候须要带上这个token。 那么问题是前端代码发送申请的时如何获取这个token呢? 在Rails中,如果你是应用form helper的话,在后端render的时候,会从session中去读取这个token并插入到form的hidden field中。如果你是通过FE JS 发送ajax申请的话,你须要从本站的layout的meta tag中去读区这个token。 所以对于在第三方站点(B站)上的申请来讲,它是得不到这个token的(如果他曾经能失去这个token,阐明他曾经有了session,也就没必要再通过B站来发申请了),所以这个申请在服务器端将会无奈通过验证。 补充信息:Rails在比拟token是否统一的时候,有一个对request.base_url 和 request.origin的比拟。这里base_url指的是这次申请的domain地址,origin指的是这个申请是从哪里来的。请看上面的例子:假如咱们在站点Bhttps://websiteb.com触发了一个到站点Ahttps://websitea.com的申请:POST https://websitea.com/path那么此时在A的server:request.base_url 是 https://websitea.comrequest.origin 是 https://websiteb.com

April 10, 2021 · 1 min · jiezi

关于ruby-on-rails:别梦依稀咒逝川Ruby二十八年前M1-Mac-os配置Ruby300-on-Rails6112021最新

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_188 在每个开发者心里,都会有一门“最好”的语言,在这个世界的某个深处,在一些矫矫不群的人们心中,这门语言的名字叫做Ruby,它往年二十八岁了,历史和Java一样的悠久,然而它没有大厂背书、它的性能被开发者诟病、时至今日仍然无奈高效利用多核资源,甚至于它每年都要被“死亡”一次,相比于有太阳计算机系统、甲骨文、IBM 这些大公司反对的 Java,它是那么的赤贫如洗,然而,它又领有全世界最虔诚的“信徒”,领有最沉闷的开发者社区,这所有,又让它是那么的包罗万象。是的,这就是Rubyist的理念:有的时候,你想证实给一万个人看,到起初,你发现只失去了一个明确的人,那就够了。 本次咱们尝试在最新的M1芯片Mac os(Big Sur 11.2.2)中搭建最新版Ruby3.0.0以及Web开发框架Rails6.1.1,全新的芯片、全新的征途、全新的开始: 首先咱们来看看M1芯片的命令行,如果你是从老版本Mac迁徙过去的,比方笔者(Mojave),最好将老的Base命令行更换成zsh,zsh是一款性能比bash更弱小的终端(shell)零碎,既能够作为一个交互式终端,也能够作为一个脚本解释器,这里更换必要性是指如果应用Bash编译Ruby3.0,可能会产生一些未知谬误。执行命令切换zsh: sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"装置胜利后,确保在应用程序-》实用工具-》终端-》简介中,不要勾选Rosetta,因为接下来咱们须要以arm架构的homebrew进行装置,所以所有的编译和运行动作都不须要Rosetta的参加: 随后重启终端,开始装置amr架构的Homebrew: /bin/bash -c "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh)"而后编辑配置文件 ~/.zshrc,退出如下内容: path=('/opt/homebrew/bin' $path) export PATH存盘之后执行命令: source ~/.zshrc查看新brew的地位: ➜ ~ which brew /opt/homebrew/bin/brew如果返回的是/opt/homebrew/bin/brew就阐明装置胜利,接着更新一下版本: ➜ ~ brew cleanup && brew update Already up-to-date.如果没有代理,能够抉择设置一下国内源: # brew git -C "$(brew --repo)" remote set-url origin https://mirrors.ustc.edu.cn/brew.git # core git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git # cask git -C "$(brew --repo homebrew/cask)" remote set-url origin https://mirrors.ustc.edu.cn/homebrew-cask.git echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.zprofile source ~/.zprofile接下来咱们来装置Ruby3.0,业界比拟支流的装置形式大抵两种:rvm或者rbenv,这里咱们应用rbenv,它其实就是一个相似python中conda一样的多版本治理软件包,能够不便一些老我的项目以低版本ruby运行,比方ruby2.6。 ...

March 1, 2021 · 2 min · jiezi