前言
近日接到了一个需求,需要实现消费者通过管控平台来访问页面供应商在管控平台配置的页面,而且页面供应商、管控平台、消费者有以下的特殊背景要求。
- 页面供应商
页面供应商是第三方开发者,管控平台无权要求 第三方开发者使用指定技术 开发页面,也无权要求 第三方开发者对提供给管控平台的页面进行任何兼容性开发。
- 管控平台
对页面供应商提供的页面进行管控,如页面的访问对象、访问时限等等管控操作。
- 消费者
管控平台提供链接给消费者,消费者访问该链接,就可以查看页面供应商提供的页面。消费者不接受 对管控平台的任何兼容性开发。
1、系统中如何访问第三方系统的页面
在系统中如何访问第三方系统的页面,目前市面上面有两种实现方案:微前端 和iframe。
目前比较可靠的微前端方法有乾坤微前端框架 和无界微前端框架两种。但是这两种都要求被访问的系统做一定的兼容性改造。
无界微前端框架作为一个对接入系统要求非常小的框架,在保活模式和重建模式下要求第三方系统中的资源和接口的请求都在我方系统中发起,所以会有跨域问题,第三方系统必须做 CORS 设置,也就是要求第三方系统允许我们系统跨域访问,这一般是不太可能的。
而乾坤微前端框架要求对第三方系统进行一系列的改造,如导出生命周期钩子、支持基于浏览器 history API 的路由配置等等。
在需求中管控平台只能通过iframe
来访问页面供应商提供的页面。而消费者不能为了访问管控平台做兼容开发如使用微前端框架,只能通过iframe
来访问管控平台。
但是 iframe
加载第三方页面的速度有点慢,要使用一些手段加速一下。
2、如何让iframe加载第三方页面速度变快
让iframe
加载第三方页面速度变快,除了依赖于第三方页面本身的加载速度和优化,还可以使用一些外部方法。
2.1、使用预处理技术
预处理技术包括预加载、DNS预解析、预连接技术。
- 预加载
在<head>
标签中使用<link rel="preload" href="第三方页面地址">
指令预加载iframe
内容,这样当用户到达包含iframe
的部分时,内容可能已经被加载并缓存。
html
<link rel="preload" href="https://example.com/home" as="document">
- DNS预解析
在<head>
标签中使用<link rel="dns-prefetch" href="第三方页面域名不包含包含协议">
指令进行DNS预解析,以减少iframe
加载内容时的DNS解析时间。
html
<link rel="dns-prefetch" href="//example.com">
- 预连接
在<head>
标签中使用<link rel="preconnect" href="第三方页面域名包含协议">
指令进行DNS预解析,以减少iframe
加载内容时的连接时间。
html
<link rel="preconnect" href="https://example.com">
然而在管控平台中第三方页面地址是动态获取,事先并不知道要访问那个第三方页面地址,如果要使用预处理,必须统一第三方页面的访问地址。
比如可以使用重定向方法来统一第三方页面的访问地址,根据网址上面的参数转发到不同的地址去,以下是一个简单的示例:
java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/redirectServlet")
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求参数
String destination = request.getParameter("destination");
// 根据参数值决定重定向目标
if ("site1".equals(destination)) {
response.sendRedirect("https://www.example1.com");
} else if ("site2".equals(destination)) {
response.sendRedirect("https://www.example2.com");
} else {
// 如果参数不匹配,可以选择重定向到默认页面或返回错误
response.sendRedirect("/defaultPage.html");
// 或者
// response.sendError(HttpServletResponse.SC_NOT_FOUND, "Page not found.");
}
}
}
2.2、使用CDN加速
使用CDN加速,由于提供方不一定给自己提供的页面地址进行CDN加速。所以我们需要统一给第三方页面地址进行CDN加速。
首先,需要选择一个CDN提供商,如Cloudflare、Amazon CloudFront、Akamai等。不同的提供商会有不同的服务和API接口。注册并设置好你的CDN服务后,获取必要的API访问权限,通常是API密钥或OAuth凭证。
一旦拥有API访问权限,可以使用Java代码调用CDN提供商的API来进行各种操作,如创建CDN分发、更新缓存策略、查询CDN使用情况等。这通常涉及到发送HTTP请求到CDN提供商的API端点。可以使用Java的内置类HttpURLConnection
,或者使用第三方库如Apache HttpClient或OkHttp来发送这些请求。
以下是一个使用HttpURLConnection
发送GET请求的基本示例:
java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class CDNApiExample {
public static void main(String[] args) throws Exception {
String apiUrl = "https://api.cdnprovider.com/v1/some_endpoint"; // 示例API URL
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer YOUR_API_TOKEN"); // 设置API访问令牌
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// 打印结果
System.out.println(response.toString());
}
}
调试时请将 "https://api.cdnprovider.com/v1/some_endpoint"
和 "Bearer YOUR_API_TOKEN"
替换为实际的API端点和访问令牌。
3、如何提高自己页面的加载速度
打铁还得自身硬,想让别人通过 iframe
更快,最好的办法就是自己的页面加载速度快。
3.1、衡量指标
页面加载速度的衡量可以通过多种性能指标来进行,这些指标反映了用户体验的不同方面。以下是一些最常用的性能指标:
3.1.1、FP
FP指的从页面加载开始到第一个像素绘制到屏幕上的时间。
3.1.2、FCP
FCP指的是从页面开始加载到页面上的第一个文本或图像内容出现在屏幕上的时间。这个指标反映了用户等待看到页面内容所需的时间。
3.1.3、LCP
LCP衡量的是在视口中最大的内容元素(如图像、视频或文本块)完全加载和渲染的时间。这个指标反映了主要内容成为可见所需的时间,是衡量加载性能的一个重要指标。
3.1.4、FID
FID衡量的是用户首次与页面交互(例如点击链接、按钮等)到浏览器实际能够开始处理该交互事件的时间。这个指标反映了页面的响应性。
3.1.5、Time to Fully Loaded
完全加载时间是指从用户开始访问页面到页面的所有网络活动停止的时间点,包括延迟加载的元素和与页面交互触发的网络请求。这个指标反映了页面完全可用所需的时间。
3.1.6、TTI
TTI衡量的是页面从开始加载到主要子资源加载完成并且能够快速响应用户输入的时间。这个指标反映了页面成为完全交互式的时间。
3.1.7、Speed Index
速度指数衡量的是页面内容可视化填充的速度。它显示了页面加载过程中内容填充的平均时间,帮助了解页面加载的视觉进展。
3.2、衡量工具
如何查看这些指标,可以使用谷歌浏览器开发者调试工具中的Insights(性能)工具来查看这些指标。
打开门户系统,打开开发者调试工具,按下图操作:
结果如下所示:
门户系统加载的FCP指标是9.40秒。谷歌浏览器提供评分文档
- 在0秒至1.8秒之间的FCP时间被认为是良好的
- 1.8秒至3秒之间的FCP时间需要改进
- 而超过3秒的FCP时间被认为是较差的
3.3、页面加载过程
3.3.1、DNS查询
当用户在浏览器地址栏输入一个网站地址(URL)时,浏览器首先需要找到该网站的IP地址。这通常涉及到一个DNS(域名系统)查询,以将域名解析为IP地址。
3.3.2、发起连接
浏览器使用解析得到的IP地址发起对服务器的TCP连接请求。如果网站支持HTTPS,这一步还将包括TLS握手过程,以建立一个安全连接。
3.3.3、发送HTTP请求
一旦TCP连接建立(和TLS握手完成,如果适用),浏览器会通过这个连接发送一个HTTP请求给服务器,请求网页的资源。
3.3.4、服务器响应
服务器接收到HTTP请求后,会处理这个请求,并将响应数据(通常是HTML文档)发送回浏览器。
3.3.5、解析HTML
浏览器开始解析从服务器接收到的HTML文档。解析过程中,浏览器会构建DOM(文档对象模型)树。
3.3.6、请求额外资源
在解析HTML并构建DOM树的过程中,浏览器会遇到外部资源的引用,例如CSS文件、JavaScript文件、图片等。浏览器会发起额外的HTTP请求来获取这些资源。
3.3.7、构建CSSOM树
对于每个CSS资源,浏览器会解析CSS并构建CSSOM(CSS对象模型)树。
3.3.8、渲染树构建
一旦DOM和CSSOM树都准备好了,浏览器会将它们合并成一个渲染树(Render Tree),这个树包含了所有可见元素的样式信息。
3.3.9、布局
渲染树构建完成后,浏览器会进行"布局"(Layout)过程,计算每个对象的确切位置和大小。
3.3.10、绘制
布局完成后,浏览器会进入"绘制"(Paint)阶段,将每个节点转换成实际的像素,并显示在屏幕上。
3.3.11、合成
在某些情况下,浏览器会将页面分成多个层并分别处理,然后通过"合成"(Composite)将这些层合并到一起,最终显示在屏幕上。
3.4、提高手段
3.4.1、独立工程开发
从上述的页面加载过程来看,要提高DNS查询、发起连接、发生HTTP请求、服务器详情需要在服务端优化提速,前端从解析HTML开始优化提速。
现代的前端工程构建产物,包含html文件、js文件、css文件,其中html文件内容都极少,这个解析HTML的过程速度很快,不必做过多的优化。
关键是在请求额外资源的过程中一般比较慢需要重点优化,额外资源主要是js文件、css文件,如果一个工程中引入第三方组件库越多打包后的js文件越大导致加载速度越慢。
管控平台会提供一个页面,供消费者访问,消费者可以通过这个页面来访问页面供应商提供的页面。
该页面不应该跟管控平台在同一个工程中,应该独立一个工程开发 ,相当管控平台分为配置态和运行态两个平台。在工程中,尽量少引入第三方库。
3.4.2、压缩构建产物
现在的前端框架,如UmiJS、Alita、在构建产物时都会开启默认压缩js、css的能力,无需额外配置。
在部署过程中要开启gzip压缩,不然浏览器加载还是未压缩的资源。
假如是用nginx部署,可以在nginx/conf/nginx.conf中配置
ini
http {
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_types application/javascript image/png image/gif image/jpeg text/css text/plain;
gzip_buffers 4 4k;
gzip_http_version 1.1;
gzip_vary on;
}
gzip
:on | off ,默认为off,on为开启gzip,off为关闭gzip。gzip_min_length
:number,压缩起点,文件大于多少才进行压缩,单位默认为字节,也可用k表示千字节。gzip_comp_level
:压缩级别,1-9,数字越大,压缩后的大小越小,也越占用CPU,花费时间越长。gzip_types
:需要进行压缩的文件类型。类型去Response headers中看Content-Type属性。gzip_buffers
:number size,设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。 例如 4 4k代表以4k为单位,按照原始数据大小以4k为单位的4倍申请内存。如原始数据大小为17K,则申请 (17/4)*4 = 17k内存。gzip_http_version
:设置gzip压缩针对的HTTP协议版本以上。gzip_vary
:on | off,是否在http header中添加Vary:Accept-Encoding,on表示添加。Vary:Accept-Encoding告诉代理服务器缓存两种版本的资源:压缩和非压缩,避免一个浏览器不支持压缩资源,而先请求了服务器,服务器缓存了非压缩的资源,然后一个浏览器支持压缩资源,再去请求了服务器,结果得到非压缩资源,但是又去解压它,结果会出错。所以建议设置为on。
3.4.3、CDN加速
在供消费者访问管控平台会的页面的工程部署后,配置上CDN加速。
3.4.4、Cache-Control配置缓存策略
假如是用nginx部署,可以在nginx/conf/nginx.conf中配置,使用add_header
指令来设置:
ruby
location ~* .(html|htm|js|css|jpg|jpeg|png|gif|ico|svg|webp)$ {
add_header Cache-Control "public, max-age=31536000";
}
Cache-Control: public, max-age=31536000
:这表示资源是公共的,可以被缓存,且最大年龄为31536000秒(1年)。这样浏览器和CDN等缓存服务器都可以缓存并重用这个资源,直到它过期。
4、结论
如何通过管控平台让消费者访问页面供应商配置的页面,由于微前端技术(如乾坤和无界微前端框架)需要第三方系统进行兼容性改造,这在某些情况下并不可行。因此,iframe
成为了一个无需第三方系统做出任何改动即可实现的方案。
为了提升iframe
加载第三方页面的速度,提出了以下优化措施:
- 使用预处理技术,如预加载、DNS预解析和预连接技术,来提前处理资源,减少加载时间。
- 使用CDN加速,通过统一第三方页面的访问地址并利用CDN服务加速内容分发,提高加载速度。
- 优化自身页面加载速度,通过独立工程开发、压缩构建产物、使用CDN加速和配置Cache-Control缓存策略等手段,提高页面加载效率。