一样平常开发的时间,会碰到各种各样的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处置处罚差异意题目. |