UriComponentsBuilder 拼接URL、解析URL

85 篇文章 2 订阅
35 篇文章 1 订阅

前言

  • 关于URI参考这里
  • springboot 2.1.1.RELEASE

UriComponentsBuilder

UriComponentsBuilder

  • UriComponentsBuilder 是UriBuilder的实现。针对Servlet,还派生出来ServletUriComponentsBuilder。
  • 使用过UriComponentsBuilder 的都知道,很好用

快速来个示例

String url = UriComponentsBuilder.fromUriString("http://mydomain/api/getToken")
									.queryParam("appid", "123")
									.queryParam("appsecret", "secret123")
									.build().encode().toString();
System.out.println(url);
  • 这段代码可以得到:http://mydomain/api/getToken?appid=123&appsecret=secret123
  • 这段代码实际做了几件事:
    1. 实例化 UriComponentsBuilder 。UriComponentsBuilder.fromUriString("http://mydomain/api/getToken")
    2. 设置 UriComponentsBuilder 实例。.queryParam("appid", "123").queryParam("appsecret", "secret123")
    3. 创建 UriComponents 实例。.build()
    4. 设置 UriComponents 实例。.encode()
    5. UriComponents 实例转成字符串。.toString()

实例化 UriComponentsBuilder 的方法

UriComponentsBuilder 提供的实例化 UriComponentsBuilder 的方法

public static UriComponentsBuilder newInstance();
public static UriComponentsBuilder fromPath(String path);
public static UriComponentsBuilder fromUri(URI uri);
public static UriComponentsBuilder fromUriString(String uri);
public static UriComponentsBuilder fromHttpUrl(String httpUrl);
public static UriComponentsBuilder fromHttpRequest(HttpRequest request);
public static UriComponentsBuilder fromOriginHeader(String origin);

ServletUriComponentsBuilder 提供的实例化 UriComponentsBuilder 的方法

public static ServletUriComponentsBuilder fromContextPath(HttpServletRequest);
public static ServletUriComponentsBuilder fromServletMapping(HttpServletRequest);
public static ServletUriComponentsBuilder fromRequest(HttpServletRequest);
public static ServletUriComponentsBuilder fromCurrentContextPath();
public static ServletUriComponentsBuilder fromCurrentServletMapping();
public static ServletUriComponentsBuilder fromCurrentRequest();

设置 UriComponentsBuilder 实例

赋值
.queryParam("appid", "123")
重复赋值
.queryParam("appid", "123")
.queryParam("appid", "234")
  • appid 会变为[“123”, “234”]
替换
.queryParam("appid", "123")
.replaceQueryParam("appid", "234")
  • appid 变为234
路径
.path("a")
.path("b")
.path("c")
  • xxx/a/b/c
替换路径
.path("a")
.path("b")
.path("c")
.replacePath("d")
  • xxx/d
更多

略。

关于urlencode

前面示例中.build() 中得到的是 UriComponents 派生类(HierarchicalUriComponents)的实例。
在这里插入图片描述
HierarchicalUriComponents 类的实例在.encode()时,使用HierarchicalUriComponents.encodeUriComponent() 方法进行 url 编码。其编码方式与java.net.URLEncoder的实现不同。

总结一下(代码参考测试代码1):

代码结果特征遵循协议
URLEncoder.encode(“1 + 2 = 3”, “utf-8”);1+%2B+2+%3D+3空格转义成+;+转义成%2BW3C标准规定
HierarchicalUriComponents.encodeUriComponent(“1 + 2 = 3”, “utf-8”,Type.QUERY_PARAM);1%20+%202%20%3D%203空格转义成%20;+不变RFC 3986

用哪个对呢?都对!!!但,要看提供服务的应用支持哪个。我的建议是,都试试,哪个能用用哪个。

如何让 URLEncoder 支持 空格转义成%20;+不变呢?

参考这里:https://blog.csdn.net/qq_43566496/article/details/84935364

如何让 HierarchicalUriComponents 支持 空格转义成+;+转义成%2B呢?
方法1
String url = UriComponentsBuilder.fromUriString("http://mydomain/api/getToken")
									.queryParam("appid", "123")
									.queryParam("appsecret", "secret123")
									.queryParam("q", URLEncoder.encode("1 + 2 = 3"))
									.build(true).encode().toString();
System.out.println(url);
  • .build(true) 告诉 UriComponents 我已经做过uri编码了,你就不要再做uri编码了。
方法2
String url = UriComponentsBuilder.fromUriString("http://mydomain/api/getToken")
									.queryParam("appid", "123")
									.queryParam("appsecret", "secret123")
									.queryParam("q", URLEncoder.encode("1 + 2 = 3"))
									.build().toString();
System.out.println(url);
  • 去掉.encode()UriComponents 就不要再做uri编码了。
spring 提供的支持 RFC 2396、RFC 3986 的类: UriUtils

https://docs.spring.io/spring-framework/docs/3.0.x/javadoc-api/org/springframework/web/util/UriUtils.html

测试代码1

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;

import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

public class Test {
	public static void main(String[] args) throws UnsupportedEncodingException {
		System.out.println(URLEncoder.encode("1 + 2 = 3", "utf-8"));
		System.out.println(encodeUriComponent("1 + 2 = 3", Charset.forName("utf-8"), Type.QUERY_PARAM));
	}
	
	/*HierarchicalUriComponents.encodeUriComponent() 方法的高仿实现*/
	static String encodeUriComponent(String source, Charset charset, Type type) {
		if (!StringUtils.hasLength(source)) {
			return source;
		}
		Assert.notNull(charset, "Charset must not be null");
		Assert.notNull(type, "Type must not be null");

		byte[] bytes = source.getBytes(charset);
		boolean original = true;
		for (byte b : bytes) {
			if (!type.isAllowed(b)) {
				original = false;
				break;
			}
		}
		if (original) {
			return source;
		}

		ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length);
		for (byte b : bytes) {
			if (type.isAllowed(b)) {
				baos.write(b);
			}
			else {
				baos.write('%');
				char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16));
				char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16));
				baos.write(hex1);
				baos.write(hex2);
			}
		}
		return StreamUtils.copyToString(baos, charset);
	}
	
	enum Type {

		QUERY {
			@Override
			public boolean isAllowed(int c) {
				return isPchar(c) || '/' == c || '?' == c;
			}
		},
		QUERY_PARAM {
			@Override
			public boolean isAllowed(int c) {
				if ('=' == c || '&' == c) {
					return false;
				}
				else {
					return isPchar(c) || '/' == c || '?' == c;
				}
			}
		};

		/**
		 * Indicates whether the given character is allowed in this URI component.
		 * @return {@code true} if the character is allowed; {@code false} otherwise
		 */
		public abstract boolean isAllowed(int c);

		/**
		 * Indicates whether the given character is in the {@code ALPHA} set.
		 * @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
		 */
		protected boolean isAlpha(int c) {
			return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
		}

		/**
		 * Indicates whether the given character is in the {@code DIGIT} set.
		 * @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
		 */
		protected boolean isDigit(int c) {
			return (c >= '0' && c <= '9');
		}

		/**
		 * Indicates whether the given character is in the {@code sub-delims} set.
		 * @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
		 */
		protected boolean isSubDelimiter(int c) {
			return ('!' == c || '$' == c || '&' == c || '\'' == c || '(' == c || ')' == c || '*' == c || '+' == c ||
					',' == c || ';' == c || '=' == c);
		}

		/**
		 * Indicates whether the given character is in the {@code unreserved} set.
		 * @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
		 */
		protected boolean isUnreserved(int c) {
			return (isAlpha(c) || isDigit(c) || '-' == c || '.' == c || '_' == c || '~' == c);
		}

		/**
		 * Indicates whether the given character is in the {@code pchar} set.
		 * @see <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986, appendix A</a>
		 */
		protected boolean isPchar(int c) {
			return (isUnreserved(c) || isSubDelimiter(c) || ':' == c || '@' == c);
		}
	}
}
String url = UriComponentsBuilder.fromUriString("http://api.fanyi.baidu.com/api/trans/vip/translate")
									.queryParam("appid", appid)
									.queryParam("q", encode(query))
									.queryParam("from", from)
									.queryParam("to", to)
									.queryParam("salt", salt)
									.queryParam("sign", sign)
									.build(true).encode().toString();

参考

https://www.cnblogs.com/zhengxl5566/p/10783422.html
https://www.cnblogs.com/zhengxl5566/p/13492602.html
https://www.cnblogs.com/siqi/p/10070926.html

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
拼接URL odpython是指通过将不同部分的URL组合在一起来构建一个完整的URL。这个过程可以通过使用字符串操作和URL编码技术来完成。 首先,我们需要确定需要拼接URL的各个部分。通常,一个URL由以下几个部分组成: 1. 协议:通常是http或https等。 2. 主机:即网站的域名或IP地址。 3. 端口:如果没有指定,默认是80。 4. 路径:即网站的具体页面或资源的位置。 5. 查询参数:如果有需要传递到服务器的参数,可以在URL中添加查询字符串。 6. 锚点:用于直接跳转到网页中的某个位置。 然后,我们可以使用字符串操作技术将这些部分组合在一起: ``` protocol = "http" host = "www.odpython.com" port = "80" path = "/blog" query = "category=python&page=1" fragment = "intro" url = protocol + "://" + host + ":" + port + path + "?" + query + "#" + fragment ``` 在上面的示例中,我们通过加号(+)将各个部分连接在一起,并使用冒号(:)分隔主机和端口。另外,还需要在路径前加上斜杠(/)和查询参数前加上问号(?),以及在锚点前加上井号(#)。 最后,我们得到的完整URL将是: http://www.odpython.com:80/blog?category=python&page=1#intro 需要注意的是,在拼接URL时,还需要进行URL编码,特别是对于查询参数中的特殊字符和中文字符。可以使用Python的urllib.parse模块中的quote函数来进行URL编码。 总而言之,在拼接URL odpython时,我们需要将协议、主机、端口、路径、查询参数和锚点等各个部分组合在一起,并进行URL编码,以构建一个完整有效的URL

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值