限 时 特 惠: 本站每日持续稳定更新内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: muyang-0410

大家好,今天给大家分享一份抹茶专属文档里的文章,关于url解析功能点的技术细节。

img

url能够识别高亮,并且还解析出对应网页的标题。这样点击就能跳转,不点击也能知道这个网站是干嘛用的,是不是方便很多。这样一个功能是怎么做出来的,又有哪些细节呢?本文会详细的从调研到方案选型,再到技术实现,一一道来。

背景

为啥要做这个url跳转的功能呢?首先是因为我们的项目有点赞的功能。大家为了能够获赞,就会发一些很好的博客链接。

如果这个链接能够被识别出来,点击就能跳转,是不是对大家都会很方便?甚至做的再好些,直接把url对应的标题解析出来,不用点击就知道这个链接是啥内容,我感不感兴趣。

调研

url的识别其实很简单,一般就是正则匹配。url的标题解析也很简单,就是提前访问一下,然后获取对应网站的title标签内容。

那难点在哪里呢?

难点在于,你什么时候去解析或者匹配url。是后端做还是前端做,是入库时做,还是列表查询做?

和前端的消息体是怎么样的?

于是我们先调研了一下市面上已经成熟的产品,相信大家并不陌生,就是我们的知识星球。

img

熟悉星球的小伙伴应该都知道,星球会解析url的标题。我们通过抓包就可以了解他们实现的思路。

打开F12,抓到了这么多包,不知道哪个是我们想要的内容。

img

这时候交大家一个小技巧,通过内容搜索请求,ctrl+f出现搜索框搜索Git

img

点击info下的消息体,复制出来发现被编码了,进行解码一下。

img

后端是直接在原文用一种特殊格式传给前端,里面指定了title文本内容和跳转链接。

我们要不要学它这么去做呢?

方案选型

首先我们思考下url什么时候去解析。url的正则匹配不怎么耗时,主要是请求外部网站解析标题的时候比较耗时。

img

你可以选择:

发送消息,入库前去解析

用户访问消息列表的时候,查出来在后端解析

直接原文扔给用户,前端自己去解析。

首先排除2,总共才一份消息。不同的人请求,都要去重复解析,拉高的整体的接口响应,占用了后端的资源。

3和2的区别在于,3是用户端自己解析,不会占用服务的资源。这样消息阅读者的加载会慢一些。但是它有个致命的缺点,如果你在千人在线的群发一条链接。这一千个前端都会去请求那个网站,解析url,对别人的网站负担比较大。我们还是不要给别人的网站造成这样的困扰比较好。

思来想去,就剩最后一个选择了。那就是让消息的发送者稍微委屈下(谁让你要发链接呢!)。

那有没有可能异步呢?也不要去阻塞发送者。先入库,再异步解析,再推送给其他用户。

答案是否定的,消息发送者其实也需要实时看见自己的链接被解析了。这个时间与其都要等,不如就直接等着吧。

于是最终我们决定让消息发送者承担下所有,但是别太悲观,该有的优化,我们也会尽力去优化的。

技术实现

在技术实现之前,我们需要先进行一个最小粒度的验证。就是先验证我们能够识别url和标题解析,再去进行代码更优雅的编写。

尝试识别url

public static void main(String[] args) {
String content = "这是一个很长的字符串再来 www.github.com,其中包含一个URL www.baidu.com,, 一个带有端口号的URL http://www.jd.com:80, 一个带有路径的URL http://mallchat.cn, 还有美团技术文章https://mp.weixin.qq.com/s/hwTf4bDck9_tlFpgVDeIKg";
Pattern pattern = Pattern.compile("((http|https)://)?(www.)?([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?");
List matchList = ReUtil.findAll(pattern, content, 0);//hutool工具类
System.out.println(matchList);
}

输出的结果

[www.github.com, www.baidu.com, http://www.jd.com:80, http://mallchat.cn, https://mp.weixin.qq.com/s/hwTf4bDck9_tlFpgVDeIKg]

大部分的case都匹配上了,没有问题。其实想要找一个完美的链接匹配正则是有难度的。这个正则还是一个粉丝用gpt4生成的。

尝试获取标题

获取标题,我们可用java常用的爬虫工具Jsoup来进行内容的解析。一般浏览器展示的标签页的文本,就是html里面的标签

public static void main(String[] args) throws IOException {
Connection connect = Jsoup.connect("http://www.baidu.com");
Document document = connect.get();
String title = document.title();
System.out.println(title);
}

输出结果

百度一下,你就知道

为了让你能更加清楚的了解jsoup爬取到的是啥样,我们debug看看

img

其实就是一个html页面。我们通过.title()去匹配标题的标签内容。

所有网页的标题都是这个title标签吗?也不全是。比如微信文章的网页。

,你去访问这个title是拿不到任何东西的

img

因为它压根就没有title标签。通过深入分析它的html文档,你会发现,它的标题是在标签里,也有一定的规律。

img

找到了规律,就能匹配出我们的标题

public static void main(String[] args) throws IOException {
Connection connect = Jsoup.connect("https://mp.weixin.qq.com/s/O4Ts0UnnDlYB5OQyCxO0Og");
Document document = connect.get();
String title = document.getElementsByAttributeValue("property", "og:title").attr("content");
System.out.println(title);
}

这样就能解析出我们的标题了。

你发现没,不同的页面,标题在不同的标签内,需要不同的解析方式。我们也不知道哪些标题需要用到什么解析方式,只能把解析不出来的标题打个日志,然后再去慢慢的添加更多的解析方式,那未来肯定会扩展很多的解析方式。

把标题的解析方式做成解析器。每个解析器串成一个链条。通用的解析器优先级更高。链条中直到其中某个解析器解析出标题,就返回。

解析器串起的链条就是责任链模式,创建责任链的地方就是工厂模式。而不同的类实现不同的url解析方法,这就是策略模式,而抽象类里面的逻辑,又像是模板方法模式,一口气就能实现四种模式。

搭建url解析框架

正好想到之前学源码的时候,看见的参数解析器(就是识别方法的参数名)和我们的这个需求类似,我们可以参考去进行框架的搭建。

img

定义接口,核心的接口是,其他的方法只是细分的获取步骤。

img

公共的逻辑放在抽象类。子类和WxUrl就是不同的标题解析策略。

img

img

img

是我们的策略类,同时也是组装责任链的工厂。如果你调用它,它会按顺序执行责任链,直到解析出url标题。

img

看源码能让我们更加深入的理解设计模式的运用,更能为我们平时的开发提供思路灵感

这样一个url解析框架基本完成,发送消息的时候只需要匹配出所有url,然后通过责任链去解析标题就ok了。

真的ok了吗?

并行解析

如果一个用户发了一大段话,里面有非常多个url,我们要串行的去一步步解析吗。

img

耗费的时间是每一个网址解析时间的总和。每个网址的解析其实互不相关,完全可以独立进行。

img

这样立马就省下了大多数的时间,好歹消息的发送者是要阻塞在这里的url解析,也要考虑下它的体验吧。

这样还不够,针对这种网站,请求时间可能会很长,它决定了用户的等待上限。我们要对它们做一个熔断,也就是超过1s,没拿到网站,就算了。对于代码就是这样。

Connection connect = Jsoup.connect(matchUrl);
connect.timeout(1000);
return connect.get();

img

解析超时直接丢弃。这样的一个并行框架要怎么去写呢?可以用,不了解的要去先学学JUC,然后再看看美团的一篇技术文章:。

美团提供了一个异步的工具类,对进行了一层封装,用起来更加简洁优雅。

com.abin….utils..over#

img总结

看完本篇文章,你能了解到一个简单的url解析框架的从0到1,为什么要做这个功能?调研了哪些方案?方案选型的思考?最小粒度的技术尝试?以及为了支持灵活的扩展与性能做出的框架的搭建过程。

当你明白这些之后,就像是自己从0到1的搭建了这个框架,还有谁会质疑?

完成该功能可体现出:

爬虫框架jsoup的灵活运用,与生成正则对工作的加成(解决问题的能力)

参考框架,写出一套适合自己场景的URL解析框架。体现你对源码的熟悉程度。与对大量设计模式的熟练度。

对并发框架的熟悉程度,以及平常阅读技术博客的习惯,并能灵活运用。

你需要准备:

多了解设计模式,以及它们可能会对应被提问的问题。

提前把JUC学好,对你的工作,源码阅读,面试,都有很高性价比

深入阅读源码,或者其他框架代码,比如dubbo,netty

对应的学习路线与资源,可参考《阿斌Java之路》的知识库

欢迎大家加入,阅读专属的抹茶项目文档url解析,内含所有功能点的技术细节。

限 时 特 惠: 本站每日持续稳定更新内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: muyang-0410