news 2026/4/16 14:44:58

Android Url的一些常见处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android Url的一些常见处理

日常开发的时候,会遇到各种各样的Url.这里就总结一些常见的Url遇到的一些问题,以及对应的处理方式

常见问题

  • 参数问题
  • 重定向问题
  • Url长度问题
  • Url传递过程中编码问题
1.Url 参数处理

1.1 获取Url 指定参数的值

/** * 获取Url的原来参数值 */ fun getQueryParameterValue(url: String, key: String): String? { if (TextUtils.isEmpty(url) || TextUtils.isEmpty(key)) return url var uri = Uri.parse(url) if (uri.isOpaque()) { return url } //利用Map的唯一性拼接参数 var parameterMap = getParameterMap(url) return parameterMap.get(key) } /** * 获取Url参数的值(Decode之后的) * * getQueryParameter() 方法是默认Decode的 * */ fun getQueryParameterDecodeValue(url: String, key: String): String? { if (TextUtils.isEmpty(url) || TextUtils.isEmpty(key)) return "" var uri = Uri.parse(url) if (uri.isOpaque()) { return "" } else { return Uri.parse(url).getQueryParameter(key) } } /** * 把url 的参数转为Map存储 */ private fun getParameterMap( url: String ): HashMap<String, String> { var map: HashMap<String, String> = HashMap<String, String>() // 参数名字的列表 var parameter = Uri.parse(url).queryParameterNames parameter.forEach { if (getQueryParameterDecodeValue(url, it) != null) map.put(it, getQueryParameterDecodeValue(url, it)!!) } return map }

1.2 添加和删除指定参数

/** * 删除Encode 的参数 */ fun deleteQueryParameterDecodeValue(url: String, key: String): String { if (TextUtils.isEmpty(url) || TextUtils.isEmpty(key)) return url var uri = Uri.parse(url) if (uri.isOpaque()) { return url } if (!url.contains("?")) { url + "?" } var urlStart = url.split("?").get(0) //利用Map的唯一性拼接参数 var parameterMap = getParameterMap(url) //利用map的唯一性 存储或者更新值 if (parameterMap.containsKey(key)){ parameterMap.remove(key) } //参数的map var appendUrl = appendMapParameter(parameterMap) var division = "?" return "$urlStart$division$appendUrl" } /** * 添加 Encode 的参数 */ fun addQueryParameterDecodeValue(url: String, key: String, value: String): String { if (TextUtils.isEmpty(url) || TextUtils.isEmpty(key)) return url var uri = Uri.parse(url) if (uri.isOpaque()) { return url } if (!url.contains("?")) { url + "?" } var urlStart = url.split("?").get(0) //利用Map的唯一性拼接参数 var parameterMap = getParameterMap(url) //利用map的唯一性 存储或者更新值 parameterMap.put(key, Uri.encode(value)) //参数的map var appendUrl = appendMapParameter(parameterMap) var division = "?" return "$urlStart$division$appendUrl" } /** * url 添加参数 */ fun addQueryParameterValue(url: String, key: String, value: String): String { if (TextUtils.isEmpty(url) || TextUtils.isEmpty(key)) return url var uri = Uri.parse(url) if (uri.isOpaque()) { return url } if (url.contains("#")) { url.replace("#", "%23") } if (!url.contains("?")) { url + "?" } var urlStart = url.split("?").get(0) //利用Map的唯一性拼接参数 var parameterMap = getParameterMap(url) //利用map的唯一性 存储或者更新值 parameterMap.put(key, value) //参数的map var appendUrl = appendMapParameter(parameterMap) var division = "?" return "$urlStart$division$appendUrl" } /** * map 拼接成字符串 */ private fun appendMapParameter(parameterMap: HashMap<String, String>): String { var stringBuilder = StringBuilder() parameterMap.keys.forEach { stringBuilder.append(it).append("=").append(parameterMap.get(it)).append("&") } if (stringBuilder.length > 0) { stringBuilder.deleteCharAt(stringBuilder.length - 1) } return stringBuilder.toString() } /** * 把url 的参数转为Map存储 */ private fun getParameterMap( url: String ): HashMap<String, String> { var map: HashMap<String, String> = HashMap<String, String>() // 参数名字的列表 var parameter = Uri.parse(url).queryParameterNames parameter.forEach { if (getQueryParameterDecodeValue(url, it) != null) map.put(it, getQueryParameterDecodeValue(url, it)!!) } return map }
2.获取重定向地址的真实地址
package com.wu.base.util; import android.text.TextUtils; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.concurrent.TimeUnit; import io.reactivex.Observable; import io.reactivex.ObservableOnSubscribe; import io.reactivex.ObservableSource; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /** * @author wkq * @date 2022年07月22日 16:15 * @des 重定向Url处理工具 */ public class UrlRedirectUrlUtil { //是否Encode private static boolean isEncode = false; private static Disposable callDisposable; //获取重定向后的真实地址 public static String getRedirectUrl(String path) { boolean isEncode = false; if (TextUtils.isEmpty(path)) { return ""; } if (findEnd(path)) { return path; } if (isShortUrl(path)) return path; try { if (path.contains("#")) { path = path.replace("#", URLEncoder.encode("#")); isEncode = true; } OkHttpClient mOkHttpClient = new OkHttpClient(); Request request = new Request.Builder() .addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8") .addHeader("Accept-Encoding", "gzip, deflate, br") .addHeader("Accept-Language", "zh-CN,zh;q=0.9") .addHeader("Connection", "keep-alive") .addHeader("User-Agent", "Mozilla/5.0 (Linux; Android 5.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36") .url(path) .build(); Call mCall = mOkHttpClient.newCall(request); Response response = mCall.execute(); String backUrl = response.header("Location"); if (response.code() != HttpURLConnection.HTTP_MOVED_TEMP && response.code() != HttpURLConnection.HTTP_MOVED_PERM) { String requestPath = response.request().url().toString(); if (isEncode) { requestPath = requestPath.replace("%23", URLDecoder.decode("%23")); isEncode = false; } return requestPath; } else { return getRedirectUrl(backUrl); } } catch (Exception e) { e.printStackTrace(); return path; } } //处理重定向的Url public static void getRedirectUrl(String url, ResponseCallBack callBack) { if (callBack == null) return; //取消上一个请求 cancelRequest(); if (TextUtils.isEmpty(url)) { callBack.getRedirectFail(); return; } if (findEnd(url)) { callBack.getRedirectSuccess(url); return; } if (isShortUrl(url)) { callBack.getRedirectSuccess(url); return; } callDisposable = Observable .create((ObservableOnSubscribe<String>) emitter -> { if (url.contains("#")) { isEncode = true; emitter.onNext(url.replace("#", URLEncoder.encode("#"))); } else { emitter.onNext(url); } emitter.onComplete(); }) .flatMap((Function<String, ObservableSource<String>>) s -> new Observable<String>() { @Override protected void subscribeActual(Observer<? super String> observer) { Request.Builder builder = new Request.Builder(); builder.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); builder.header("Accept-Encoding", "gzip, deflate, br"); builder.header("Accept-Language", "zh-CN,zh;q=0.9"); builder.header("Connection", "keep-alive"); builder.header("User-Agent", "Mozilla/5.0 (Linux; Android 5.0; AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Mobile Safari/537.36"); Request request = builder.url(s).get().build(); OkHttpClient client = new OkHttpClient() .newBuilder() .followRedirects(false) .connectTimeout(10, TimeUnit.SECONDS)//设置连接超时时间 .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS)//设置读取超时时间 .build(); client.writeTimeoutMillis(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { observer.onError(new Throwable("解析失败")); } @Override public void onResponse(Call call, Response response) throws IOException { String path = url; if (response.code() == HttpURLConnection.HTTP_MOVED_TEMP || response.code() == HttpURLConnection.HTTP_MOVED_PERM) { String location = response.headers().get("Location"); if (!TextUtils.isEmpty(location)) { path = location; } if (isEncode) { path = path.replace("%23", URLDecoder.decode("%23")); isEncode = false; } } observer.onNext(path); observer.onComplete(); } }); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( path -> callBack.getRedirectSuccess(path), throwable -> callBack.getRedirectFail()); } // 取消请求 public static void cancelRequest() { if (callDisposable != null && !callDisposable.isDisposed()) { callDisposable.dispose(); } } /** * 判断是否是是讯云短连接 * * @param url * @return */ public static boolean isShortUrl(String url) { return false; } /** * 判断外部链接.MP4结尾 */ public static boolean findEnd(String url) { if (url.endsWith(".mp4")) { return true; } return false; } public interface ResponseCallBack { void getRedirectSuccess(String url); void getRedirectFail(); } }
3.处理地址过长问题

日常开发的时候有一些三方SDK对Url的长度做出了限制,再加上日常使用过程中Url贼长让需要对Url做操作的同事极度反感,这个时候就需要对很长的Url做处理,以下是个人对长连接做的处理

  • 缩短器:后台来个长变短的服务,其实也就是一个字符串变短的算法,移动端请求接口即可
  • 对Url的参数进行编码使参数变短
4.Url参数编码问题

Url在分享,浏览器打开的时候中文或者特殊字符会影响Url的使用,所以在给Url处理参数的时候,给参数做统一编码(Encode)显得特别重要.假如是复杂和长期维护的项目,建议项目架构的时候就处理掉这个问题,不然后期会疯(亲身经历).

总结

日常开发中,会遇到各种各样的Url,所以涉及到的Url处理也就各种各样,建议将Url做一个统一进出的工具 统一管理各种Url的操作.其中涉及到的Url参数转码问题要慎重,要提前和H5和IOS沟通好防止出现Url处理不同意问题.

AI大模型学习福利

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。


因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 13:00:06

从零开始:使用LangChain+FastAPI构建RAG系统,掌握异步处理与文档检索核心技术

本文详细介绍了如何使用LangChain和FastAPI构建和部署检索增强生成(RAG)系统。内容包括RAG工作原理、关键组件、环境搭建、文档加载与处理、向量存储、检索器设置、API开发及异步处理。通过完整代码示例展示了从原型开发到实际部署的全过程&#xff0c;帮助开发者构建可扩展的R…

作者头像 李华
网站建设 2026/4/16 12:25:29

30岁转行AI大模型,刚好赶上风口!非常详细收藏我这一篇就够了

引言 “30岁&#xff0c;人生过半&#xff0c;转行还来得及吗&#xff1f;”这是很多人在职业瓶颈期的自我怀疑。但我想告诉你&#xff0c;30岁转行AI大模型&#xff0c;不仅来得及&#xff0c;还刚好赶上了风口&#xff01; 我是如何从一个传统行业的从业者&#xff0c;成功转…

作者头像 李华
网站建设 2026/4/15 17:13:18

Ryuko-NEHT Reloaded! MAME 0.116 游戏合集

Ryuko-NEHT Reloaded! MAME 0.116 游戏合集 站在巨人的肩上&#xff0c;走的更远。 镜像/应用大全&#xff0c;欢迎访问 一键模型下载&#xff0c;推理&#xff0c;微调&#xff0c;合并工具。 # 一锤定音&#xff08;大模型工具&#xff09; ms-swift 是魔搭社区提供的大模型…

作者头像 李华
网站建设 2026/4/16 12:55:26

MAME Ryuko-NEHT Reloaded 0.116 游戏列表与ROM信息

MAME Ryuko-NEHT Reloaded 0.116 游戏列表与ROM信息 站在巨人的肩上&#xff0c;走的更远。 镜像/应用大全&#xff0c;欢迎访问 一键模型下载&#xff0c;推理&#xff0c;微调&#xff0c;合并工具。 # 一锤定音&#xff08;大模型工具&#xff09; 一个脚本&#xff0c;支…

作者头像 李华
网站建设 2026/4/15 14:16:35

Ultralytics YOLOv8 使用指南与实战

Ultralytics YOLOv8 使用指南与实战 在智能安防、自动驾驶和工业质检等场景中&#xff0c;实时目标检测已成为不可或缺的技术。然而&#xff0c;构建一个高效、稳定且易于部署的视觉系统往往面临诸多挑战&#xff1a;环境配置复杂、依赖冲突频发、推理性能难以优化……有没有一…

作者头像 李华
网站建设 2026/4/16 12:52:22

利用CVE-2017-8890漏洞ROOT天猫魔屏A1

利用CVE-2017-8890漏洞ROOT天猫魔屏A1 本来对阿里的东西挺有好感的&#xff0c;天猫魔屏这玩意儿买回来还能当投影仪看个电影&#xff0c;结果越用越不对劲——系统封闭不说&#xff0c;连个ADB都没有。想装点第三方软件&#xff1f;门都没有。 后来偶然翻到一个老帖子说可以…

作者头像 李华