在日常的开发过程中,本地代码远程调试一直是最理想的开发状态。本文通过介绍京东集团内开发的一个轻量简单的小工具”localhost”,从多角度的方案思考,到原理介绍,到最终的方案落地,在开发阶段发现问题,解决问题。

背景

起源

在很早之前,我参加了一个技术分享大会,当时现场是分享了一个本地在远程集群中的云原生开发方案,当时听完了之后就对其中本地开发的同时可以远程运行服务这部分非常感兴趣,本身作为前端开发来说,确实每次验证一些问题的时候,在本地开发阶段无法在真实的环境中调试,需要本地测试,打包,发版,验证,在处理一些兼容问题的时候,这个过程可能要重复很多次,会浪费很多时间。同时作为赛博云测的开发来说,在云测平台上经常会遇到一些前端开发同学需要调试不同设备的兼容问题,有的甚至顶不住需要线下借设备。云测平台存在的意义的就是能够线上化解决一切移动端的问题,开发的问题也是问题。

痛点

试想这样一个场景,测试同学上报了一个手机页面打开白屏的问题,云测平台上这个手机确实复现了这个问题,你搜索了一些可能的处理方式,然后修改发版验证,发现并没有用,这个时候该怎么办。

或者后端同学提前开发完,发了测试环境给前端同学实时调试接口,需要不停的修改字段或者逻辑或者debug调试问题,这个时候该怎么办。

又或者低代码的开发同学,写完物料组件之后想在实际设备中看看效果,但是不得不单独找设备来看,或者等测试同学报bug,时间都浪费在这个过程中,该怎么办。

我想开发同学或多或少都经历过这些场景,在联调或者调试一些问题的时候,总是没办法做到本地改完代码保存立马就能查看。作为一个工具平台,怎么去解决这个痛点并且能够更好的和平台结合,这个想法就一直在我心里存在着。

思考

从听那场分享会的时候,我就已经在想有什么方案可以实现这个目的,当时分享中说到了云原生开发的本地代码的处理部分,让我没想到的是,他们的方案非常直接,直接到将本地代码“搬”到了远程,实时在本地保存的时候将代码同步到远程的开发容器中,并且为了解决 http 协议传输的时间消耗,自定义了一套协议进行代码的同步,当然这个方案对于我所设想的场景实在是大材小用了,不过真的非常胆大心细,也给我了很多思路。

在后面的时间,借着代码同步的思路,我又设想了云 IDE 这个方案,本身代码同步的目的就是希望本地代码可以在远程运行,那直接通过云 IDE 开发,并直接运行服务,这样运行的服务也是在远程的,可以直接访问。这个思路是没问题的,但是按照目前大家的开发习惯,云 IDE 不是长久之计,况且为了这个想法,开发一套云 IDE,为了一口醋包了一顿饺子,可以,但没必要∠( ᐛ 」∠)_。

之后又和有些同事聊前端开发的问题,聊到了这个想法,给我提供了一个新的思路,通过 whistle 代理和 webpack 插件的方式,webpack 插件以监听模式打包,实时上传编译后的代码到远程服务器,whistle 代理用来解决调试过程中的一些问题。当然这个方案是公司其他的同学在很早之前就已经开发出来了,名字叫 Carefree,不过现在已经不维护了,比较可惜。这个方案只能解决前端开发同学的需求,并且云测平台上我们对代理服务器有些单独的处理,不是很适合。

中间又过了一段时间,我设想了一下这个需求的最终形态,之前的方案都非常重,如果我做为使用者,可能就是在难用和难受之间徘徊(没有说之前方案不好的意思,只是不适合这个需求...),我想它足够的简单和轻量,没有什么环境准备工作,拿来就能用。那最简单的方式就是不在代码上面下功夫,而是转向服务,只要维护好服务上的请求和响应,能够和本地进行交互,就可以达到我想法中所要求的。这个时候,我的想法聚集到了一个方向——内网穿透。

市面上的内网穿透的应用有很多,这又涉及到了另一个问题,安全,如果内网穿透滥用的话,很可能会造成隔离的内网服务被映射到外网从而被攻击,那损失就是把我卖了都赔不了...并且私下使用内网穿透本身也不好控制和追溯,有很大的安全隐患。

纠结了很长时间,既然不让偷偷用,那就光明正大的用,我可以自己实现一个应用,只要限制好功能和安全边界就可以了(已经和安全部门报备过了,放心)。而且自己实现,可以满足自己的所有想法,轻量简单,和云测平台结合等等,没有什么可以比实现自己的想法还令人激动的事情啦。于是便有了下面的内容。

localhost 是什么

介绍

localhost 是一个使用 Go 语言编写的轻量简单的内网穿透工具。这个工具支持 web 服务的映射,会将启动在本地 localhost 中的服务映射到远程服务器上,在访问远程对应的服务时,实际请求会利用本地和远程已经建立的隧道发送到本地服务中,达到访问本地服务的目的。为什么要使用 Go 来写呢,相对于其他的语言,Go 编译简单且编译完没有额外的运行环境要求,本地交叉编译可以得到各类系统的可执行文件,对于使用者来说非常友好。

使用

帮助文档在这里:localhost 帮助文档,可以在帮助文档里或者在赛博云测平台的云真机使用页面内进行工具下载。

就如上面说到的,localhost 是轻量简单的,使用方式非常简单,它是一个独立的可执行文件,启动的参数只有两个,启动方式如下:

# windows
localhost.exe -token xxxxxxxx -port xxxx # mac
localhost -token xxxxxxxx -port xxxx

-token 这个参数是当次使用的 token,可以在赛博云测平台的云真机使用页面上申请,每次的有效期半小时。

-port 这个参数是当前本地启动的服务的端口。

在设计客户端这部分的时候,为了尽可能降低大家的使用门槛,特意将参数设计的尽可能少,port 端口参数是必不可少的,那为什么还设计需要一个 token 参数呢,这个参数的初衷是为了识别用户的身份,类似于 ssh 协议的 key,使得行为可追溯,后来利用 token 来控制使用行为,比如单次使用有效期等等。其他的参数在不影响功能和安全的前提下,都被我排除掉了,希望它使用足够简单。

原理

整体工具分为三个部分:服务端,客户端,web 端。服务端和客户端是进行服务映射的主要部分,包含了建立通道,通道转发之类的逻辑。web 端提供了一些交互的接口,路由聚合代理转发的处理。

核心逻辑

localhost 最核心的部分就是内网穿透,它是由服务端和客户端共同完成实现的。众所周知本地启动的服务,只能本地或局域网内访问到,远程设备无法访问本地服务,但是本地的设备可以访问远程的服务,通过本地访问远程时建立的隧道进行通信,来达到远程设备能够访问本地服务的目的。

整体流程图如下:

首先在服务器中,启动了 web 端部分的服务,是整体服务中的底层服务的调度部分,其中提供了一些 client 端调用的 web 接口以及用户请求时的反向代理等功能,web 端服务是长期运行在远程服务器上,在下面会详细说明这部分做了什么。

client 端会分发给内部同学下载使用,在运行 client 端的时候,client 调用 web 的服务,启动对应的 server 端,并且将相关参数信息传入,并返回给 client 端。

server 端启动的时候,会启动监听两个端口服务,一个是监听用户请求的端口,一个是监听 client 端这边的隧道连接端口,当 client 端主动发起和远程服务器进行连接时,通过当前这个连接打通通信隧道,当用户请求进来时,通过已经建立的通信隧道,将请求报文转发到本地 client 端。

client 端启动完成,并且调用 web 端服务成功返回之后,client 端拿到相关信息连接对应的 server 端,隧道建立成功之后,等待服务端转发过来的请求信息。当监听到请求过来时,client 端会主动连接启动的指定端口的本地服务,并且将请求报文转发给当前的本地服务,同时,响应报文也会通过已有的链路原路返回,最终回到开始的请求方。

通过这种方式,就可以达到远程访问本地服务的目的,通过中转服务器进行服务的穿透,并且这种方式不需要用户关注中间过程,只需要启动提供的 client 端服务,使用简单,基本没有使用成本,不会影响代码。

路由聚合反向代理

使用过程中可能有的同学会有这样一个疑问,在 client 端启动完成之后,会返回显示访问的链接,为什么访问这个链接就可以直接访问到自己本地的服务呢?在 client 端启动时,会调用 web 端的接口服务,这个时候会记录当前的用户身份,并且在启动 server 端时,将启动的 server 端口与当前的用户 erp 形成一个映射关系,并且根据当前这个 erp 建立一个反向代理的规则。在 web 端启动的服务中,有一个监听当前请求的服务,当任何地方访问 web 端的服务时,会对访问的路由进行监听判断,如果能匹配到已有连接的 erp 信息,就会将当前访问请求报文转发到对应的 server 端服务中,然后 server 端再将请求转发到对应的 client 端。

流程图如下:

另外,在通过第一次通过聚合的 erp 路由访问之后,会记录当前访问的 ip,将 ip 与 erp 映射关系也对应上,这样,在后续的访问中,路由可以不用携带 erp 信息,也同样能够映射到当前自己的本地服务,这样可以解决一些静态资源的访问路径的问题,也可以用来解决 history 路由访问的情况。

未来

history路由处理

当前端工程的路由采用的 history 模式的时候,在上述的 erp 聚合的路由就会出现 history 路由访问不对的情况,虽然可以通过第一次访问 erp 路由之后去除 erp 来访问,但是总体来说还是会带来一些困扰,后续计划采用泛域名解析,去除路由上的处理,将用户标识通过域名来解析,路由回归用户原本的样子,这样不会造成额外的困扰和理解上的成本。

支持https

当前 localhost 工具在交互的过程中整体流程上还是 http 协议,目前只能通过把本地工程的 https 配置去除才能使用,但是和有的同学沟通下来发现有的工程中 https 请求是必须的,所以后续将会支持 https,后续设想在访问时只要是 https 的请求,就默认访问本地项目的 https,不需要额外的显式配置或声明。

结束

本地代码的远程之路,在整个过程中经历了很多方向,也产生了很多想法,最终诞生了 localhost 这个工具,在后续的时间会结合更多的场景,继续完善这个工具,希望能够让大家在工作的过程中,多快好省。

作者:京东零售 谢天

来源:京东云开发者社区 转载请注明来源

localhost工具:本地代码的远程之路的更多相关文章

  1. 5000字长文,kurryluo 的自学编程之路

    我是程序员.大众口中非科班的那种,带着高中时期对二进制的恐惧,在大学参加科研比赛后保研,再到和校友一起创业,现在在某大型互联网公司做前端开发,一路走来都是靠自己学习. 前端框架 VUE 的作者尤大说过 ...

  2. 远程之SSH

    SSH(Secure Shell的缩写),由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为建立在应用层和传输层基础上的安全协议.SSH 是目前较可靠,专为远 ...

  3. 平板点餐软件编程体会---记我的Android编程之路

    前言 想开发一个平板点餐系统,研究下陈江根大侠分享的一个很高水准的实例,只是个单机版无实用意义. (如需运行源码请回复联系邮箱) 实现 Mysql 数据库+Tomcat WEb服务器,使用Servle ...

  4. 01-Python的介绍_Python编程之路

    首先用一句业内非常出名的话来介绍Python "人生哭短,我用Python" 这也是Python宣传时经常说的一句话 从这句话中,可以非常清楚Python他到底优点在哪里,为什么要 ...

  5. 07_Python的控制判断循环语句1(if判断,for循环...)_Python编程之路

    Python的数据类型在前几节我们都简单的一一介绍了,接下来我们就要讲到Python的控制判断循环语句 在现实编程中,我们往往要利用计算机帮我们做大量重复计算的工作,在这样的情况下,需要机器能对某个条 ...

  6. PHP并发IO编程之路

    并发IO问题一直是服务器端编程中的技术难题,从最早的同步阻塞直接Fork进程,到Worker进程池/线程池,到现在的异步IO.协程.PHP程序员因为有强大的LAMP框架,对这类底层方面的知识知之甚少, ...

  7. 使用localhost调试本地代码,setcookie无效

    今天在本地调试代码的时候,再域名中使用localhost,结果一直调试不成功,最后发现在登录时,setcookie()没有设置进去 于是发现了,在使用localhost调试时,保存cookie是无效的 ...

  8. 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6621566 上一篇文章Android进程间通信 ...

  9. 02-Python的下载和安装_Python编程之路

    原文发布在特克斯博客www.susmote.com 之前给大家讲了关于python的背景知识,还有Python的优点和缺点,相信通过之前的介绍很多人已经清楚自己到底要不要选择学习Python,如果已经 ...

  10. 03-第一个脚本程序以及输入输出_Python编程之路

    上节课已经教大家安装了Python的解释器,那么这节课我们就可以正式来写代码了 说明:在下面的代码演示中,我将大部分使用python交互器演示代码的输入输出,注意">>>& ...

随机推荐

  1. Ubuntu安装后续工作

    更新源: sudo gedit /etc/apt/sources.list 清华的源 deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial ma ...

  2. 谁家面试往死里问 Swagger 啊?

    大家好,我是小富- 前言 说个挺奇葩的事,有个老铁给我发私信吐槽了一下它的面试经历,他去了个国企单位面试,然后面试官跟他就Swagger的问题聊了半个多小时.额- 面试嘛这些都不稀奇,总能遇到是千奇百 ...

  3. Python 导入 Excel多sheet

    Python 导入 Excel多sheet 假设表格的样式如下 import os import sys import django BASE_DIR = os.path.dirname(os.pat ...

  4. MediaBox助力企业一站式获取音视频能力

    以一只音视频百宝箱,应对「千行千面」. 洪炳峰.楚佩斯|作者 大家好,今天我分享的主题是MediaBox--行业音视频数字化再加速. 根据权威数据表明,65%的行业数字化信息来自视频,基于此,音视频技 ...

  5. Win10 误删winsock注册表修复。 winsock.reg

    手贱删除了注册表的winsock项, 导致无法上网. 导入后需要重启电脑才能上网, 这个文件是我在别人电脑里导出来的. 下载地址: https://pan.baidu.com/s/1wH8SdeWsx ...

  6. flask中cookies的使用

    flask中cookies的使用 在Flask中对cookie的处理 1. 设置cookie: 设置cookie,默认有效期是临时cookie,浏览器关闭就失效 可以通过 max_age 设置有效期, ...

  7. 一个 println 竟然比 volatile 还好使?

    前两天一个小伙伴突然找我求助,说准备换个坑,最近在系统复习多线程知识,但遇到了一个刷新认知的问题-- 小伙伴:Effective JAVA 里的并发章节里,有一段关于可见性的描述.下面这段代码会出现死 ...

  8. 文心一言 VS 讯飞星火 VS chatgpt (105)-- 算法导论10.1 3题

    三.用go语言,仿照图 10-2,画图表示依次执行操作 ENQUEUE(Q,4).ENQUEUE(Q,1).ENQUEUE(Q,3).DEQUEUE(Q).ENQUEUE(Q,8)和 DEQUEUE( ...

  9. ERROR: nginx-1.22.1 installation failed.

    libraries. You can either do not enable the module or install the libraries.make: *** No rule to mak ...

  10. 11g编译bbed

    报错如下: make -f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed Linking BBED utility (bbed) rm -f /u01/app/or ...