掘金「跳转外链风险提示」实现思考

3,531 阅读4分钟

大家好,我是张三岁🤣,一只法系前端⚖️。爱分享🖋️、爱冰冰🧊🧊。
欢迎小伙伴们加我微信:maomaoibingbing,拉你进群,一起讨论,期待与大家共同成长🥂。

前言

网页的安全性优化是一个越来越被开发者重视的问题(例如配置 SSL 证书实现网站的 https 访问,通过插件对 XSS 攻击进行预防等),今天我们就来分析 掘金 是如何实现网站跳转外部链接时“拦截”并通知的功能。

一、业务场景

掘金 的文章或者沸点中打开一个链接时,如果为 外部链接 (非本站的链接)时,则会先跳转至一个风险提示的页面,告知用户即将打开的新页面 出现任何问题概不负责 非本站提供,注意账号财产安全。其实就是一个免责的声明。(以下将用一篇文章中的某个外部链接做演示。因为这个网站的加载动画非常好康

掘金跳转外链效果图.gif

其中最主要的提示页面如下图:

掘金风险提示页.png

二、代码分析

1. 链接元素

我们需要对其代码(可见的)进行分析,首先关注点击跳转的元素。打开控制台 检查元素 查看此链接元素有什么特殊的地方。

链接元素.png

通过上图我们可以直观看出链接前被拼接了掘金内部链接 https://link.juejin.cn/?target= ,而 = 后的网址才是真实网址。

2. 风险提示

然后我们再来看下风险提示页。

掘金风险提示页.png

风险提示 页,只需将 URL 上的 target 参数取出并显示在页面中即可。(URL传参常见于各类搜索页面)

3. 链接处理

当然还有关键的一环是,这个链接是何时被处理成这样的。先来看看是不是在编辑文章时处理的。

编辑文章.png

从上图可知,编辑文章时链接并未实时做处理。我们知道掘金的文章草稿是实时保存的,那么我们来看下请求中发送的数据是否做了处理。

查看编辑文章时的请求.gif

编辑文章请求.png

从发送的请求中可以看出字段 mark_content 中的链接并未作处理,则链接应该是在后台被处理的。

三、进行编码

1. 风险提示页面

掘金的技术栈是 Vue2.x ,此处给出 Vue2.x 版本的写法:

// 风险提示页
<template>
  <div class="box">
    <div class="tip-box">
      <img
        class="logo"
        src="https://lf-cdn-tos.bytescm.com/obj/static/link_juejin_cn/assets/logo_new.0ec938fb.svg"
      />

      <div class="content">
        <div class="title">
          <del>冰冰你个小可爱</del> 即将离开稀土掘金,请注意账号财产安全
        </div>
        <div class="link">{{ target }}</div>
        <button class="btn" @click="navigateToTarget">继续访问</button>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "RiskTip",
  data() {
    return { target: "" };
  },
  methods: {
    // 获取 url
    getTargetURL() {
      const query = window.location.href.split("?")[1] || "";
      const target = query.split("target=")[1] || "";
      this.target = window.decodeURIComponent(target);
    },
    // 跳转页面
    navigateToTarget() {
      if (!this.target) {
        return;
      }

      window.location.href = this.target;
    },
  },
  mounted() {
    this.getTargetURL(); // 获取 url
  },
};
</script>

<style scoped>
.box {
  height: 100vh;
  background-color: #f4f5f5;
}

.box .tip-box {
  position: absolute;
  left: 50%;
  top: 30%;
  max-width: 624px;
  width: 86%;
  background-color: #fff;
  transform: translateX(-50%);
  padding: 30px 40px 0;
  box-sizing: border-box;
  border: 1px solid #e5e6eb;
  border-radius: 2px;
}

.box .tip-box .logo {
  display: block;
  width: 116px;
  height: 24px;
  position: absolute;
  top: -40px;
  left: 0;
}

.box .tip-box .content .title {
  font-size: 18px;
  line-height: 24px;
}

.box .tip-box .content .link {
  padding: 16px 0 24px;
  border-bottom: 1px solid #e5e6eb;
  position: relative;
  color: gray;
  font-size: 14px;
}

.box .tip-box .content .btn {
  display: block;
  margin: 20px 0 24px auto;
  color: #fff;
  border-radius: 3px;
  border: none;
  background: #007fff;
  height: 32px;
  font-size: 14px;
  padding: 0 14px;
  cursor: pointer;
  outline: 0;
}
</style>

让我们来康康效果如何:

自定义风险提示页.gif

2. 前端链接处理

由请求传参可知,富文本中的链接并未作处理,那如果我们需要前端做处理然后再返回给后台的话,就需要借助正则表达式,替换所有富文本中的链接。这里我们封装一个公共方法:

// utils/index.js
/**
 * 替换富文本中的链接
 * 将富文本中的不是本站的链接前追加 "https://link.juejin.cn/?target="
 * @param    html  传入富文本
 * @returns  html  处理后的富文本
 */
export const replaceHTMLHref = (html) => {
  const juejinReg = /https:\/\/juejin.cn/g; // 匹配"https://juejin.cn"
  const juejinSignReg = /JUEJIN_URL/g; // 匹配"JUEJIN_URL"
  const urlReg =
    /((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*(?!juejin.cn)[\w\-\@?^=%&/~\+#])?)/g; // 匹配所有网址

  /**
   * 匹配替换三次
   * 第一次将所有"https://juejin.cn"替换为"JUEJIN_URL"
   * 第二次将所有网址增加前缀"https://link.juejin.cn/?target="
   * 第三次将所有"JUEJIN_URL"替换为"https://juejin.cn"
   */
  const result = html
    .replace(juejinReg, "JUEJIN_URL")
    .replace(urlReg, "https://link.juejin.cn/?target=$1")
    .replace(juejinSignReg, "https://juejin.cn");
  return result;
};

我们写一段代码测试一下,康康他是否生效:

// 省略其他非关键代码
import { replaceHTMLHref } from "@/utils";

const str = '一个外部网址:\nhttps://webgradients.com/\n又一个外部网址:\nhttps://www.baidu.com/\n掘金:\nhttps://juejin.cn/';
console.log(replaceHTMLHref(str));

测试公共方法.png

至此,前端处理富文本中的链接的功能已实现。

四、掘金彩蛋

在查看编辑文章请求的时候偶然发现,编辑文章页面的控制台会打印如下内容:

编辑文章控制台彩蛋.png

控制台彩蛋很多网站都有,但不得不说,掘金官方还真是蛮可爱的。٩('ω')و

小结

通过检查元素、查看请求等方式,推导了掘金「跳转外链风险提示」的可能实现方式。但相信我们从此案例中收获到的不仅仅是一种解决方案,更是一种处理问题的思路。我们只有不断向优秀的项目学习,才能更好的提升自己的技术水平。