java之长链短链详解,实现重定向短链转长链

相关文章:
java之net.http.HttpClient详解
Java Uri和Url及Uri解析过程

什么是短链长链:

长链接:

长链是完整的URI,包含协议、域名、路径和查询参数等信息。例如,https://www.example.com/page?param1=value1&param2=value2 就是一个长链。

短链接:

短链是对长链进行简化的一种形式,通常由一个较短的字符串表示。短链可以通过将长链映射到一个短字符串来实现,这个映射关系存储在数据库或者其他数据结构中。用户在访问短链时,系统会将其转换为对应的长链并进行跳转。短链的好处是更易于记忆和分享。

短链场景:

  • 微博评论→ 存在字符数限制,使用短链节省空间
  • 短链生成二维码更加简单,提高设备识别率

原理

  • 请求短链:向服务器发送一个HTTP请求,其中包含短链的URL。
  • 服务器根据短链接key获取对应长链接
  • 通过HTTP 301/302请求转发到对应长链接

难点:

  • 异常场景:
    • url如何解析,传入的一定是合法?不合法又是怎么解析,怎么判断是域名导致,是什么导致
    • url过期是怎么做的,不能直接报错
    • 短链服务问题,无法解析,dns刷不到,找不到域名,(并不局限于此,正式场景一次请求即可判断)

为什么要使用GET?

"GET"是HTTP协议中的一种请求方式,主要用于获取资源。在这个场景中,你正在请求一个URL,所以"GET"是合适的请求方法。 不显示设置请求方法,HttpURLConnection默认的请求方法也为”GET”;

为什么重定向能获取到长链

如果在一个HTTP请求的响应中,服务器返回了一个重定向的HTTP状态码(例如301, 302, 303等),并且提供了一个新的URL,那么**HttpClient.Redirect.NORMAL**策略会让HttpClient自动发起一个新的请求到这个新的URL,从而获取新URL的响应。

长短链代码优化:

  1. HttpClient的重复创建:在**createshortUnCompress方法中,都创建了新的HttpClient对象。由于HttpClient对象可以安全地在多个线程之间共享,因此通常建议将其作为单例来使用。你可以将其初始化为类的静态成员,这样就只会创建一次HttpClient**,并在所有的请求中复用。注意!!这是因为他线程安全
  2. 异常处理:在**create方法中,你捕获了IllegalArgumentException并抛出了自定义的Kxxxxxxx,这很好,因为它使异常信息更加清晰。然而,这个方法还可能抛出其他的未检查异常,例如IOExceptionInterruptedException。你可能需要考虑这些异常的处理策略,比如是直接抛出,还是转换为Kxxxxx**。
  3. 正则表达式的编译:在**getabc**方法中,你在每次调用时都编译了同一个正则表达式。编译正则表达式是一个相对昂贵的操作,如果正则表达式是不变的,你可以将其作为类的静态常量,只编译一次。

优化后代码如下,但是只提供一种思路并不适合正式场景,如请求次数过多影响性能。

import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class ShortLinkUtil {

    private static final String URL_AUTHORITY = "x";
    private static final int PATH_NUM = 8;
    private static final int SUCCESS_RESPONSE = 200;
    private static final Pattern ABC_PATTERN = Pattern.compile("abc=([^&]*)(&|$)");
    private static final HttpClient CLIENT = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL).build();

    private ShortLinkUtil() {
        throw new IllegalStateException("Utility class");
    }
    /**
     * 获取abc
     *
     * @param url
     * @throws IOException
     * @throws InterruptedException
     */
    public static String getabc(String url) throws IOException, InterruptedException, xxxxxxxxx {
        String paramInfo = shortUnCompress(url).getQuery();
        Matcher matcher = abc_PATTERN.matcher(paramInfo);
        if (!matcher.find()) {
            throw new xxxxxxxx("xxxxxxxx不存在,请检查url果然是");
        }
        return matcher.group(1);
    }

    /**
     * 获取longUrl
     *
     * @param shortUrl
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    @Deprecated(forRemoval = false)
    public static URI shortUnCompress(String shortUrl) throws IOException, InterruptedException, xxxxxxxxxxxx {
        URI uri = create(shortUrl);
        HttpResponse<String> response = sendHttpRequest(uri);
        URI resultURL = response.uri();
        if (uri.equals(resultURL)) {
            throw new xxxxxxxxxxxx("链接失效" + shortUrl);
        }
        return resultURL;
    }

    /**
     * 查验格式、可用性 & 创建url
     * @param str
     * @return
     * @throws xxxxxxx
     */
    private static URI create(String str) throws xxxxxxxx {
        URI uri;
        try {
            uri = URI.create(str); //基本格式验证
        } catch (IllegalArgumentException e) {
            throw new xxxxxxxxxxx("URL格式不合法" + str, e);
        }
        String scheme = uri.getScheme();
        if (scheme == null) {
            throw new xxxxxx("URL格式不合法" + str);
        }
        scheme = scheme.toLowerCase(Locale.US);
        if (!(scheme.equals("https") || scheme.equals("http"))) {
            throw new Kxxxxx("");
        }
        try {
            InetAddress.getByName(uri.getHost()); //判断dns,,不需要
            HttpResponse<String> response = sendHttpRequest(uri);
            if (response.statusCode() != SUCCESS_RESPONSE) {
                throw new xxxxxxx("解析失败" + str);
            }
        } catch (UnknownHostException e) {
            throw new xxxxx("解析DNS失败" + uri.getHost());
        } catch (IOException | InterruptedException e) {
            throw new xxxxx("请求失败");
        }

        return uri;
    }

    /**
     * 发送请求
     * @param uri
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    private static HttpResponse<String> sendHttpRequest(URI uri) throws IOException, InterruptedException {
        HttpRequest request = HttpRequest.newBuilder()
                .uri(uri)
                .GET()   // This is the default
                .build();
        return CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值