一个改变url格式的类

class Prourl {
        /**
         * URL路由,转为PATHINFO的格式
         */ 
        static function parseUrl(){
            if (isset($_SERVER['PATH_INFO'])){
                       //获取 pathinfo
                $pathinfo = explode('/', trim($_SERVER['PATH_INFO'], "/"));  //使用 / 将当前路径分割为数组
            
                       // 获取 control
                       $_GET['m'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index');   //如果第一个参数不为空则为第一个,否则跳到index

                       array_shift($pathinfo); //将数组开头的单元移出数组  array_shift()函数删除数组中的第一个元素,并返回被删除元素的值。
                      
                       // 获取 action
                       $_GET['a'] = (!empty($pathinfo[0]) ? $pathinfo[0] : 'index');
                array_shift($pathinfo); //再将将数组开头的单元移出数组 

                for($i=0; $i<count($pathinfo); $i+=2){
                    $_GET[$pathinfo[$i]]=$pathinfo[$i+1];
                }
            
            }else{    
                $_GET["m"]= (!empty($_GET['m']) ? $_GET['m']: 'index');    //默认是index模块
                $_GET["a"]= (!empty($_GET['a']) ? $_GET['a'] : 'index');   //默认是index动作
    
                if($_SERVER["QUERY_STRING"]){
                    $m=$_GET["m"];
                    unset($_GET["m"]);  //去除数组中的m
                    $a=$_GET["a"];
                    unset($_GET["a"]);  //去除数组中的a
                    $query=http_build_query($_GET);   //形成0=foo&1=bar&2=baz&3=boom&cow=milk格式
                    //组成新的URL
                    $url=$_SERVER["SCRIPT_NAME"]."/{$m}/{$a}/".str_replace(array("&","="), "/", $query);
                    header("Location:".$url);
                }    
            }
        }
    }

复习几个常见的函数  

1. explode(separator,string,limit)       separator 用什么分割   string  需要分割的字符串  
返回的是一个数组
2.
3.http_build_query      生成urlencode格式
 
这种类的好处就是可以有利于seo,使爬虫更加容易识别。

转载于:https://www.cnblogs.com/Bl4ckc0de/p/3598917.html

<think>我们有一个需求:移除URL中的指定参数键值对。例如,给定一个URL字符串,我们想要移除其中特定的查询参数(key)及其对应的值(value)。思路:1.解析URL,将其分解为基本部分(协议、主机、路径等)和查询字符串部分。2.解析查询字符串,将其转换为一个键值对集合(如Map)。3.从这个集合中移除指定的参数(一个或多个)。4.重新构建查询字符串(注意:如果移除后查询字符串为空,则整个查询部分应该去掉)。5.将基本部分和新的查询字符串(如果有的话)组合成新的URL。注意:URL中可能存在多个同名的参数(虽然不常见,但是允许的),我们需要移除所有指定key的参数。我们可以使用Java标准库中的`java.net.URI`和`java.net.URL`,但要注意这两个在解析和构建时的行为差异。另外,我们也可以使用`java.net.URLDecoder`和`URLEncoder`来处理编码问题。但是,由于URL的查询字符串是键值对,我们可以自己处理查询字符串部分,而不必依赖第三方库。步骤详细说明:1.将URL字符串分解为两部分:base部分(不包含查询字符串)和查询字符串(如果有的话)。2.将查询字符串解析为参数列表。我们可以使用`String.split`方法,按照`&`分割,然后每个键值对再按照`=`分割。注意,值可能包含`=`,所以我们只分割第一个`=`。另外,参数可能没有值(只有key)。3.将解析出来的参数存入一个List或Map中?但是考虑到同一个key可能有多个,我们使用List来存储每一个参数(每个参数是一个键值对对象,或者两个分开的字符串)。我们也可以使用`MultiValueMap`(如Spring框架中的),但这里我们使用标准Java,所以用List存储键值对,然后过滤掉要移除的key。4.然后,重新构建查询字符串:遍历过滤后的列表,将每个键值对进行URL编码(如果需要的话)并用`=`连接,然后用`&`连接所有键值对。5.将base部分和新的查询字符串组合起来。注意:在构建新的查询字符串时,我们需要对键和值进行URL编码吗?实际上,原始URL中的键值对可能是已经编码过的。我们不应该解码,因为如果解码后再编码,可能会改变原始字符(比如原始是编码过的,我们解码后可能得到非URL安全的字符,再编码可能和原来不同)。所以,我们直接操作原始字符串?但是这样也有问题:我们移除参数时,需要匹配的是解码后的key还是原始字符串的key?考虑:用户传入的key是未编码的,而URL中的key可能是编码过的。所以我们需要将用户传入的key进行编码,然后去匹配URL中已经编码的key?或者将URL中的key解码后与用户传入的key比较?这两种方式都可以,但需要统一。为了准确匹配,我们可以这样:-将URL中的每个参数的键和值都进行URL解码(使用UTF-8),然后与用户传入的key(未编码)进行比较。这样,用户传入的key就是原始字符串,而不管URL中该key是编码还是未编码,我们都能匹配到。-但是,这样有一个问题:如果URL中同一个key有的编码有的未编码,我们无法区分。所以,我们也可以要求用户传入的key是原始字符串(未编码),然后我们在匹配时,将URL中的每个参数的键进行URL解码,再与用户传入的key比较。这样,无论URL中该key是编码还是未编码,我们都能移除。但是,重新构建查询字符串时,我们使用原始的键值对字符串(未解码)?不行,因为我们要移除匹配的参数,所以必须知道每个参数的原始键(未解码)是否与目标key匹配。然而,我们无法直接匹配,因为原始键可能是编码的。因此,我们采用以下步骤:1.将URL字符串拆分为base部分和查询字符串部分。2.如果查询字符串为空,则直接返回原始URL。3.将查询字符串按`&`拆分成多个参数段。4.遍历每个参数段,将每个参数段按第一个`=`拆分成键和值(如果没有`=`,则整个字符串作为键,值为空)。5.对每个键进行URL解码(使用UTF-8),然后与用户传入的key(未编码)比较。如果不相等,则保留这个参数段(注意:保留的是原始字符串,而不是解码后的)。6.将保留的参数段用`&`连接起来。7.如果保留的参数段不为空,则新的URL为base部分加上`?`加上新的查询字符串;否则,只保留base部分。这样,我们只移除了那些键(解码后)等于指定key的参数段。注意,我们保留了原始参数段的字符串(没有修改),所以编码情况保持不变。但是,有一个特殊情况:如果用户传入的key本身是编码过的,而我们用UTF-8解码后与它比较,那么可能匹配不上。所以,我们要求用户传入的key是未编码的原始字符串。另外,如果URL中有锚点(fragment)部分,我们也需要保留。所以,我们需要将URL拆分为:协议、主机、路径、查询、锚点。但是,使用`URI`可以方便地拆解。我们可以使用`URI`来解析,但是`URI`在解析不合法的URL时可能会抛出异常。所以,如果URL格式不规范,我们可能需要更灵活的处理。另一种方法是使用正则表达式,但正则表达式比较复杂,容易出错。我们选择使用`java.net.URI`解析,然后获取各个部分。但是注意,`URI`不能直接修改查询参数,所以我们需要自己处理查询字符串。步骤:1.将URL字符串构造成`URI`对象。2.获取原始URI的各个部分:scheme,host, port, path, query, fragment。3.处理query部分:按上述方法移除指定key。4.重新构建URI:使用`URI`的构造方法,传入scheme,userInfo,host,port,path,query(新的查询字符串),fragment。但是,如果原始URL没有查询字符串,query部分为null,那么我们就跳过移除操作。代码示例:注意:由于`URI`构造方法要求各个部分,我们可以这样:但是,`URI`的构造方法比较复杂,我们也可以使用`URIBuilder`(来自Apache HttpClient),但这里我们不想引入外部库,所以使用标准库。标准库中,我们可以这样构造新的URI:```javanewURI(scheme, authority, path, query, fragment); //或者newURI(scheme, host, path, query, fragment); ```但是,authority包含用户信息、主机和端口。所以,我们需要从原始URI中提取authority?或者我们可以分别提供用户信息、主机和端口?但是标准库没有提供这样的构造方法。我们可以使用多个参数的构造方法: ```javapublic URI(String scheme, StringuserInfo, Stringhost,int port, Stringpath,String query, Stringfragment)```所以,步骤:1.解析原始URL为`URI`对象。2.获取:scheme, userInfo,host,port,path,query,fragment。3.处理query:移除指定key。4.用这些部分构造新的URI(注意:port为-1表示未指定端口)。但是,如果原始URL是相对URL,那么可能没有scheme和host,所以我们需要处理相对URL。但是,`URI`可以处理相对URL。在构造时,如果某些部分不存在,可以传入null。所以,我们写一个工具方法: ```javapublicstatic StringremoveQueryParam(String urlString,String key) throwsURISyntaxException{URI uri= newURI(urlString);Stringscheme= uri.getScheme();String userInfo =uri.getUserInfo();String host= uri.getHost();int port= uri.getPort();String path= uri.getPath();String query= uri.getQuery();String fragment= uri.getFragment();//处理查询字符串if(query!= null) {//拆分查询字符串String[]params= query.split("&");List<String>remainingParams= newArrayList<>();for(Stringparam :params){//将参数拆分为键和值String[] pair= param.split("=",2); //分成两部分StringparamKey= pair[0];StringparamValue= pair.length >1? pair[1] :null;//对键进行URL解码(使用UTF-8)以便比较String decodedKey;try{decodedKey= URLDecoder.decode(paramKey, "UTF-8");}catch (UnsupportedEncodingExceptione){//一般不会发生,使用原始键decodedKey= paramKey;}//如果解码后的键不等于目标key,则保留这个参数if(!decodedKey.equals(key)) {//注意:这里保留原始字符串(param),而不是重新编码remainingParams.add(param);}}//重新构建查询字符串if (!remainingParams.isEmpty()){query =String.join("&", remainingParams);}else {query= null; //没有剩余参数,设为null}}//构造新的URIURI newUri =new URI(scheme,userInfo, host, port, path, query, fragment);return newUri.toString(); }```但是,上面的方法有一个问题:如果原始查询字符串中参数键的编码方式不是UTF-8(虽然UTF-8是标准)?另外,如果参数值包含`&`,则会被错误分割。但是,我们使用`split("&")`是安全的,因为参数值中的`&`应该被编码为`%26`,所以不会分割。但是,在拆分参数时,我们使用`split("&")`,如果参数值中包含未编码的`&`,那么就会出错。但按照标准,查询字符串中的参数分隔符是`&`,而参数值中的`&`必须编码为`%26`。所以,如果原始URL不规范(包含未编码的`&`),那么我们的方法就会出错。但这是原始URL的问题,我们假设传入的URL是规范化的。另外,在拆分键值对时,我们使用`split("=",2)`,这样可以避免值中包含`=`被拆分。但是,我们并没有对参数值进行解码,因为比较的是键,而且我们只对键进行解码(用于比较)。所以,值中的`=`不会影响。另外,如果参数没有值(只有键),那么`pair`数组长度为1,我们将其值设为null,然后保留原始字符串(即`param`就是`key`,没有等号)也是正确的。但是,当我们重新构建查询字符串时,我们使用原始的参数段字符串。这样,如果原始参数段是`key=value`,我们保留`key=value`;如果原始参数段是`key`,我们保留`key`(没有等号)。这是正确的。测试用例:原始URL:http://example.com?name=John&age=20移除key为"age",则新URL:http://example.com?name=John原始URL:http://example.com?name=John&age=20#section1移除"name",则新URL:http://example.com?age=20#section1原始URL:http://example.com?color=red&color=blue移除"color",则新URL:http://example.com原始URL:http://example.com?key=value&key2=val%26ue移除"key2",则新URL:http://example.com?key=value原始URL:http://example.com?%E4%B8%AD%E6%96%87=test(其中键是“中文”的URL编码)移除key为"中文",则新URL:http://example.com注意:在比较时,我们将键`%E4%B8%AD%E6%96%87`解码为"中文",然后与用户传入的"中文"比较,相等,所以移除。但是,如果用户传入的key是编码后的字符串(比如用户传入"%E4%B8%AD%E6%96%87"),那么解码后是"中文",而用户传入的是编码字符串,那么我们希望移除键为"%E4%B8%AD%E6%96%87"的参数?但是我们的方法要求用户传入未编码的原始字符串。所以,我们需要在文档中说明:key参数应该是未编码的字符串。如果用户确实想用编码后的key来移除,那么我们可以提供另一个方法,让用户指定是否已经编码?或者我们同时支持?但这样复杂了。我们要求用户传入未编码的key,这样更直观。另外,如果URL中有空格等字符,`URI`在解析时可能会标准化(比如将空格转为%20),所以重新构建的URL可能会和原始URL有细微差别(比如大小写)。但这是可接受的。但是,`URI`在解析和重新构建时,会对一些字符进行编码或解码,这可能会导致URL格式变化。所以,我们也可以选择不通过`URI`,而是直接操作字符串。直接操作字符串的步骤:1.将URL字符串拆分为:协议+主机+路径部分(base)和查询字符串和锚点部分。2.使用正则表达式或字符串查找来定位查询字符串的开始(`?`)和锚点的开始(`#`)。但是,这样比较麻烦。我们使用`URI`可以简化,但要注意标准化问题。权衡后,我们使用`URI`,因为它能正确处理各种情况。但是,如果URL是相对URL(没有协议和主机),`URI`也能处理。所以,我们采用上述基于`URI`的方法。另外,我们可能希望一次移除多个key。我们可以修改方法,接受一个`Set<String>`keys,然后移除所有在集合中的key。修改方法: ```javapublic staticString removeQueryParams(String urlString,Set<String> keys) throwsURISyntaxException{// ...同上//在循环内部:if (!keys.contains(decodedKey)) {remainingParams.add(param);}// ...} ```然后,我们可以提供一个移除单个key的方法,调用这个方法: ```javapublic staticString removeQueryParam(String urlString,String key) throwsURISyntaxException{return removeQueryParams(urlString, Collections.singleton(key)); }```这样更灵活。但是,如果用户传入的keys集合很大,我们可以优化:先将keys集合中的每个key进行编码(UTF-8)?但是注意,我们比较的是解码后的键,所以不需要编码keys,而是直接比较解码后的字符串。另外,注意异常处理:`URISyntaxException`和`UnsupportedEncodingException`。其中`UnsupportedEncodingException`我们可以忽略,因为UTF-8是标准编码,所以我们可以用`StandardCharsets.UTF_8`来避免异常。在Java10及以后,我们可以使用`URLDecoder.decode(paramKey, StandardCharsets.UTF_8)`,但这个方法在Java10才引入。如果使用较老的Java版本,我们可以用:```javanewString(paramKey.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8) ```但是,这样并不正确。所以,我们还是用`URLDecoder.decode`,并捕获`UnsupportedEncodingException`,但实际上不会发生,所以我们可以转为`RuntimeException`。改进:```javatry{decodedKey= URLDecoder.decode(paramKey, "UTF-8");} catch(UnsupportedEncodingException e) {thrownew RuntimeException(e);//不可能发生} ```或者,使用Java10+的`StandardCharsets.UTF_8`版本:如果项目是Java10+,我们可以使用: ```javadecodedKey= URLDecoder.decode(paramKey, StandardCharsets.UTF_8); ```但是,为了兼容Java8,我们可以这样:```javadecodedKey =URLDecoder.decode(paramKey,"UTF-8");```因为UTF-8是必须支持的。现在,我们编写工具:工具名:`UrlUtils`方法:- `public staticString removeQueryParam(String url, Stringkey)throws URISyntaxException`-`publicstatic StringremoveQueryParams(Stringurl,Set<String> keys) throwsURISyntaxException`另外,我们可以提供一个不抛出`URISyntaxException`的方法,返回原始URL当出现异常时。但是,我们让调用者处理异常,因为URL格式错误应该由调用者处理。代码实现:注意:如果URL中键的编码不是UTF-8,那么解码后可能得到乱码,导致匹配失败。但按照标准,URL编码应该使用UTF-8(现在推荐UTF-8),所以一般没问题。另外,如果原始URL的键使用了其他编码(如ISO-8859-1),那么解码就会出错。所以,我们假设URL的查询参数键是用UTF-8编码的。如果遇到非UTF-8编码的URL,那么我们的方法可能无法正确移除。但这种情况较少,而且没有标准方法可以知道URL的编码,所以我们只能假设为UTF-8。最后,我们给出完整的工具代码:注意:我们使用Java8编写,所以没有使用`StandardCharsets.UTF_8`作为参数。另外,我们也可以处理空值情况。工具代码:```javaimportjava.io.UnsupportedEncodingException; importjava.net.URI;import java.net.URISyntaxException; importjava.net.URLDecoder;import java.util.ArrayList; importjava.util.Collections;import java.util.List; importjava.util.Set;public classUrlUtils{public staticString removeQueryParam(String url, Stringkey)throws URISyntaxException {returnremoveQueryParams(url, Collections.singleton(key));}public staticString removeQueryParams(String url, Set<String>keys)throws URISyntaxException {if(url== null|| url.isEmpty()){return url;}URI uri= newURI(url);String scheme= uri.getScheme();String userInfo =uri.getUserInfo();String host= uri.getHost();int port= uri.getPort();String path= uri.getPath();String query= uri.getQuery();String fragment= uri.getFragment();if (query !=null &&!query.isEmpty()){String[]params =query.split("&");List<String> remainingParams =new ArrayList<>();for (String param: params) {String[] pair= param.split("=",2);String paramKey =pair[0];StringdecodedKey;try {decodedKey =URLDecoder.decode(paramKey,"UTF-8");} catch(UnsupportedEncodingException e) {//UTF-8 shouldbesupported,so werethrowas runtimeexceptionthrownew RuntimeException(e);}if(!keys.contains(decodedKey)){remainingParams.add(param);}}query= remainingParams.isEmpty() ?null :String.join("&", remainingParams);}//Reconstruct theURIreturnnew URI(scheme,userInfo, host, port, path, query, fragment).toString();} }```测试:我们写一个main方法测试。但是,注意:如果原始URL包含空格,`URI`构造方法会将其编码为%20,而原始URL中可能是空格或%20,所以重新构建的URL可能和原始URL不完全相同。这是标准化的结果。另外,如果原始URL的键包含加号(+),在URL编码中,加号在查询字符串中代表空格。但是,`URLDecoder.decode`方法会将加号解码为空格。所以,如果原始键是"a+b",那么解码后是"a b"。而用户传入的key如果是"a b",那么就会匹配。但是,如果用户传入"a+b",则不会匹配。这取决于用户传入的key是空格还是加号。所以,我们要求用户传入的key是未编码的原始字符串,并且按照URL编码的规则,空格在键中应该被编码为%20或+(但是,在查询字符串中,空格可以编码为+或%20,而+表示空格)。所以,用户传入的key如果是空格,那么就会匹配键为"a+b"或"a%20b"的参数(解码后都是"a b")。但是,如果用户传入的key是"a+b",那么它解码后是"ab",所以也会匹配键为"a+b"或"a%20b"的参数。所以,实际上,用户传入的key是原始字符串,不管键在URL中是编码为+还是%20,只要它们表示相同的字符串,就会匹配。所以,我们的方法在这一点上是正确的。但是,如果原始键包含加号(+),而用户传入的key是加号(+),那么解码后加号(+)会变成空格,所以不会匹配。因此,用户应该传入原始字符串,即如果键是"a+b"(字面意思是a+b,而不是a b),那么用户应该传入"a+b"。但是,在URL中,键"a+b"在查询字符串中会被写为"a%2Bb"(因为+在查询字符串中是有特殊含义的,所以如果表示字面的+,需要编码)。所以,原始URL中键为"a+b"的参数,在查询字符串中会被编码为"a%2Bb",而我们解码后得到"a+b",所以用户传入"a+b"就能匹配。所以,我们的方法是正确的。最后,我们提供这个工具给用户。注意:如果用户需要一次移除多个key,可以传入Set。相关问题:1.这个工具是否支持相对URL?是的,因为`URI`支持相对URL。在构造时,如果没有scheme和host,这些部分为null,构造出来的URI就是相对URL。2.如果URL中有多个相同的key,会全部移除吗?是的,因为我们在遍历时,每个参数都会检查,只要键匹配就移除。3.这个方法会改变URL的其他部分吗?不会,我们只修改查询字符串部分。但是,`URI`在重新构建时可能会对某些字符进行标准化编码(比如将空格转为%20),所以重新构建的URL可能和原始URL在编码上略有不同,但语义相同。4.这个方法是否线程安全?是的,工具没有共享状态,是线程安全的。5.如果URL格式错误怎么办?会抛出`URISyntaxException`,需要调用者处理。6.是否支持非UTF-8编码的URL?不支持。我们假设URL的查询参数键是用UTF-8编码的。如果遇到其他编码,可能无法正确匹配。7.如何移除多个key?使用`removeQueryParams`方法,传入一个Set。8.是否区分大小写?是的,键的比较是区分大小写的。因为`String.equals`是区分大小写的。如果希望不区分大小写,可以修改为`decodedKey.equalsIgnoreCase(key)`,但这样会改变语义。我们按照原样比较,因为查询参数的键是大小写敏感的(根据服务器而定)。所以,我们保持大小写敏感。如果需要不区分大小写,我们可以提供另一个方法。但是,我们保持简单,由调用者决定是否将key转换为小写(或大写)来匹配。例如,调用者可以这样:```javaSet<String>keysToRemove =...;//将所有要移除的key转换为小写,然后传入//但是,注意:这样也会移除那些键原本是大写的参数,而我们的工具在比较时使用的是解码后的键(原始大小写),所以我们需要在工具内部将解码后的键转换为小写,然后与转换为小写的keys比较。我们可以提供另一个方法:public staticString removeQueryParamsIgnoreCase(String url, Set<String>keys)throws URISyntaxException {//将keys转换为小写集合Set<String>lowerKeys= ...;//然后,在比较时,将decodedKey转换为小写,再与lowerKeys比较} ```但为了简单,我们不在基础工具中提供,调用者可以自己处理。因此,我们发布这个工具。注意:上面的代码中,我们使用了`String.join`,这是Java8引入的。如果使用更老的Java版本,可以用循环来拼接字符串。另外,我们也可以考虑使用`StringBuilder`来拼接查询字符串,以提高性能(特别是参数很多时)。修改构建查询字符串的部分:```javaif(!remainingParams.isEmpty()){StringBuilder sb= newStringBuilder();for(Stringparam :remainingParams) {if(sb.length()>0){sb.append('&');}sb.append(param);}query= sb.toString();} else{query =null;} ```这样,我们就不需要`String.join`了,兼容性更好(支持Java5+)。所以,最终的工具代码(兼容Java5+): ```javaimport java.io.UnsupportedEncodingException;import java.net.URI;import java.net.URISyntaxException; importjava.net.URLDecoder;import java.util.ArrayList; importjava.util.Collections;import java.util.List; importjava.util.Set;public classUrlUtils{public staticString removeQueryParam(String url, Stringkey)throws URISyntaxException {returnremoveQueryParams(url, Collections.singleton(key));}public staticString removeQueryParams(String url, Set<String>keys)throws URISyntaxException {if(url== null|| url.isEmpty()){return url;}URI uri= newURI(url);String scheme= uri.getScheme();String userInfo =uri.getUserInfo();String host= uri.getHost();int port= uri.getPort();String path= uri.getPath();String query= uri.getQuery();String fragment= uri.getFragment();if (query !=null &&!query.isEmpty()){String[]params =query.split("&");List<String> remainingParams =new ArrayList<>();for (String param: params) {String[] pair= param.split("=",2);String paramKey =pair[0];StringdecodedKey;try {decodedKey =URLDecoder.decode(paramKey,"UTF-8");} catch(UnsupportedEncodingException e) {//UTF-8 shouldbe supported, sowe rethrow asruntime exceptionthrow newRuntimeException(e);}if (!keys.contains(decodedKey)) {remainingParams.add(param);}}if(!remainingParams.isEmpty()) {StringBuildersb =new StringBuilder();for (Stringparam :remainingParams) {if(sb.length()>0){sb.append('&');}sb.append(param);}query= sb.toString();}else {query= null;}}// Reconstruct theURIreturnnew URI(scheme,userInfo, host, port, path, query, fragment).toString();} }```这样,我们就完成了工具的编写。最后,生成相关问题:</think>### Java 工具:移除 URL 中的指定参数键值对 以下是实现移除 URL 中指定参数键值对的工具,支持单个或多个参数移除,兼容特殊字符编码和复杂 URL 结构(如锚点、多值参数等)。 #### 实现代码 ```java import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.*; public class UrlUtils { /** * 移除 URL 中单个指定参数 * @param url 原始 URL * @param key 要移除的参数键 * @return 处理后的 URL 字符串 */ public static String removeQueryParam(String url, String key) throws URISyntaxException { return removeQueryParams(url, Collections.singleton(key)); } /** * 移除 URL 中多个指定参数 * @param url 原始 URL * @param keys 要移除的参数键集合 * @return 处理后的 URL 字符串 */ public static String removeQueryParams(String url, Set<String> keys) throws URISyntaxException { if (url == null || url.isEmpty()) return url; URI uri = new URI(url); String scheme = uri.getScheme(); String host = uri.getHost(); int port = uri.getPort(); String path = uri.getPath(); String query = uri.getQuery(); String fragment = uri.getFragment(); String userInfo = uri.getUserInfo(); // 处理查询参数 if (query != null) { List<String> validParams = new ArrayList<>(); for (String param : query.split("&")) { String[] kv = param.split("=", 2); // 保留值中的等号 String rawKey = kv[0]; String decodedKey = decodeUrlComponent(rawKey); if (!keys.contains(decodedKey)) { // 检查解码后的键 validParams.add(param); // 保留原始编码格式 } } query = validParams.isEmpty() ? null : String.join("&", validParams); } // 重建 URI return new URI( scheme, userInfo, host, port, path, query, fragment ).toString(); } /** * URL 解码组件(UTF-8) * @param component 编码后的字符串 * @return 解码后的字符串 */ private static String decodeUrlComponent(String component) { try { return URLDecoder.decode(component, "UTF-8"); } catch (UnsupportedEncodingException e) { return component; // 回退到原始字符串 } } } ``` #### 使用示例 ```java public static void main(String[] args) throws URISyntaxException { String originalUrl = "https://example.com/path?name=John&age=25&lang=zh_CN&color=red#section1"; // 移除单个参数 String updatedUrl = UrlUtils.removeQueryParam(originalUrl, "age"); System.out.println(updatedUrl); // 输出: https://example.com/path?name=John&lang=zh_CN&color=red#section1 // 移除多个参数 Set<String> keysToRemove = new HashSet<>(Arrays.asList("name", "color")); updatedUrl = UrlUtils.removeQueryParams(originalUrl, keysToRemove); System.out.println(updatedUrl); // 输出: https://example.com/path?lang=zh_CN#section1 } ``` #### 关键特性 1. **编码安全处理** - 自动解码 URL 参数键(UTF-8),避免编码差异导致匹配失败 - 保留原始参数编码格式(如 `%E4%B8%AD%E6%96%87` 不会被修改) - 正确处理值中的等号(如 `key=a=b` 使用 `split("=", 2)` 分割) 2. **URL 结构完整性** - 保留协议、主机、路径、锚点等非查询部分 - 自动处理端口号和用户认证信息(如 `user:pass@host`) 3. **边缘场景支持** - 空查询参数(`?` 后无内容) - 无值参数(如 `key`) - 重复参数键(移除所有匹配项) 4. **兼容性** - 基于 Java 标准库(`java.net.URI`) - 兼容 Java 8+ 环境 #### 注意事项 1. **参数匹配规则** 工具比较的是 **URL 解码后的参数键**。例如: - URL 中的 `%E6%98%8E%E6%98%9F` → 解码为 `明星` - 调用 `removeQueryParam(url, "明星")` 可移除该参数 2. **特殊字符处理** 值中的 `&` 和 `=` 会自动保留原始编码(如 `%26` 和 `%3D`),确保 URL 有效性。 3. **异常处理** 无效 URL 会抛出 `URISyntaxException`,建议调用时捕获处理: ```java try { String safeUrl = UrlUtils.removeQueryParam(invalidUrl, "key"); } catch (URISyntaxException e) { // 处理无效 URL } ``` --- ### 相关问题 1. **如何处理 URL 中的特殊字符(如空格、中文)?** 工具内部使用 UTF-8 自动编解码,调用时直接传入未编码的字符串(如 `"中文参数"`)即可匹配[^1]。 2. **能否保留参数值中的原始编码格式?** 是的,工具仅解码用于键匹配,重建 URL 时保留原始编码格式。 3. **如何适配非 UTF-8 编码的 URL?** 需修改 `decodeUrlComponent()` 方法中的字符集,例如 `"GBK"`,但建议统一使用 UTF-8 标准[^2]。 4. **是否支持批量移除参数?** 支持,通过 `removeQueryParams(url, Set<String> keys)` 可一次性移除多个参数键。 5. **如果参数键在 URL 中重复出现会怎样?** 所有匹配键名的参数都会被移除(例如 `?color=red&color=blue` 移除后为空)[^3]。 [^1]: URL 参数规范要求特殊字符必须编码,工具自动处理此过程。 [^2]: 现代 Web 标准推荐 UTF-8 编码,参考 [RFC 3986](https://tools.ietf.org/html/rfc3986)。 [^3]: 多值参数的处理取决于服务器实现,工具确保彻底移除所有匹配项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值