如何对URL字符串进行百分号编码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何对URL字符串进行百分号编码相关的知识,希望对你有一定的参考价值。

参考技术A   RFC3986 编码查询字符串
  在 RFC3986 的第2.3节列出了你不需要百分号编码的字符,因为它们在URL中没有特殊的含义。
  ALPHA / DIGIT / “-” / “.” / “_” / “~”
  α/数字/”-”/”.”/”_”
  第3.4节也解释了因为查询往往会本身包含一个URL,最好不要百分号编码斜杠(“/”)和问号(“?”)。这也是受欢迎的ios HTTP网络库Alamofire采取的方法,这给了我信心。
  因此,用RFC 3986编码一个兼容性的查询,我们可以百分号编码如上所述以外的所有字符。这很简单,如果我们首先构建一组允许的字符,然后用stringByAddingPercentEncodingWithAllowedCharacters去编码剩余的。
  注意:苹果已经在iOS 9中弃用了stringByAddingPercentEscapesUsingEncoding或CFURLCreateStringByAddingPercentEscapes这两个方法。
  Swift
  首先,swift String extension:

 

  extension String
  func stringByAddingPercentEncodingForRFC3986() -> String?
  let unreserved = "-._~/?"
  let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
  allowed.addCharactersInString(unreserved)
  return stringByAddingPercentEncodingWithAllowedCharacters(allowed)
  
  
  

  Object-C
  我们可以用Object-C的NSString的分类来做相同的事。

  @implementation NSString (URLEncoding)
  - (nullable NSString *)stringByAddingPercentEncodingForRFC3986
  NSString *unreserved = @"-._~/?";
  NSMutableCharacterSet *allowed = [NSMutableCharacterSet alphanumericCharacterSet];
  [allowed addCharactersInString:unreserved];
  return [self stringByAddingPercentEncodingWithAllowedCharacters: allowed];
  
  @end
  

  用例

  // Swift
  let query = "one&two =three"
  let encoded = query.stringByAddingPercentEncodingForRFC3986()
  // "one%26two%20%3Dthree"
  
  // Objective-C
  NSString *query = @"one&two =three";
  NSString *encoded = [query stringByAddingPercentEncodingForRFC3986];
  // "one%26two%20%3Dthree"
  

  对x-www-form-urlencoded进行编码
  推荐W3C html5 对表单数据编码是相似的,但是和RFC 3986有一点不同。在第4.10.22.5节中告诉我们下列字符是不应该百分号编码:
  ALPHA / DIGIT / “*” / “-” / “.” / “_”
  α/数字/”-”/”.”/”_”
  你应该用“+”(0x2B)代替空格(“ ”)。它和RFC 3986 的不同在 Stack Overflow answer 里有描述。波浪号(“~”)被百分号编码了,但是星号(“*”)没有。该建议很好地总结了这种情况:这种编码的表单数据在很多方面是异常的,多年来的实践的问题和折中解决导致了互通性的一系列必要操作。但是绝不代表好的设计实践。
  Swift
  给String extension添加一个新的方法

  public func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String?
  let unreserved = "*-._"
  let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
  allowed.addCharactersInString(unreserved)
  
  if plusForSpace
  allowed.addCharactersInString(" ")
  
  
  var encoded = stringByAddingPercentEncodingWithAllowedCharacters(allowed)
  if plusForSpace
  encoded = encoded?.stringByReplacingOccurrencesOfString(" ",
  withString: "+")
  
  return encoded
  
  

  注意,由于很多 web服务好像不关心我用“+”或者百分号编码将空格做了可选的编码。
  Object-C
  Object-C的方法缺少一个可选参数

  - (nullable NSString *)stringByAddingPercentEncodingForFormData:(BOOL)plusForSpace
  
  NSString *unreserved = @"*-._";
  NSMutableCharacterSet *allowed = [NSMutableCharacterSet alphanumericCharacterSet];
  [allowed addCharactersInString:unreserved];
  if (plusForSpace)
  [allowed addCharactersInString:@" "];
  
  NSString *encoded = [self stringByAddingPercentEncodingWithAllowedCharacters:allowed];
  if (plusForSpace)
  encoded = [encoded stringByReplacingOccurrencesOfString:@" " withString:@"+"];
  
  return encoded;
  
  

  用例:

  // Swift
  let query = "one two"
  let space = query.stringByAddingPercentEncodingForFormData()
  // "one%20two"
  
  let plus = query.stringByAddingPercentEncodingForFormData(true)
  // "one+two"
  
  // Objective-C
  NSString *query = @"one two";
  NSString *encodedQuery = [query stringByAddingPercentEncodingForFormData:YES];
  // "one+two"
  
参考技术B 百度UrlEncode编码
原理:编码方法很简单,在该字节ascii码的的16进制字符前面加%. 如 空格字符,ascii码是32,对应16进制是'20',那么urlencode编码结果是:%20
注:采用不同的字符集,编码结果可能不同哈

如何在 C# 中对字符串进行 URL 编码

【中文标题】如何在 C# 中对字符串进行 URL 编码【英文标题】:How to URL encode strings in C# 【发布时间】:2014-03-27 15:46:31 【问题描述】:

我们如何在 C# 中使用 URL (RFC 1738) 标准对字符串进行编码?

以下在线工具正在使用此标准 http://www.freeformatter.com/url-encoder.html 转换字符串

我要转换的字符串示例是test(brackets),编码后的字符串应如下所示:

test%28brackets%29

【问题讨论】:

URL Encoding using C#的可能重复 【参考方案1】:

Uri.EscapeDataString 做你想做的事。见MSDN。

【讨论】:

对不起,它不起作用。试过这个字符串 str = "test(brackets)"; str = Uri.EscapeDataString(str); 奇怪。当我尝试 "string result = Uri.EscapeDataString("test(brackets)");"结果是“test%28brackets%29”。在你的系统上 EscapeDataString 之后 str 有什么值? 字符串保持不变。它不会改变 Uri.EscapeDataString changed with .NET 4.5 包含 RFC 3986 字符的行为。 @Dirk:感谢您提供的信息。事实上,我的目标是 .NET 4.5。【参考方案2】:

根据RFC 1738:

Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL.

HttpUtility.UrlEncodeWebUtility.UrlEncode 都不会对这些字符进行编码,因为标准规定括号 () 可以不编码使用。

我不知道您链接的 URL Encoder / Decoder 为什么会对它们进行编码,因为它还将它们列为可在 URL 中使用的字符。

【讨论】:

我正在通过 HTTP 调用第三方 API 并在参数中传递一个字符串。此字符串是 UTF-8 URL 编码的。我的 API 客户端是用 asp.net C# 编写的,而 API 主机可能是用 Java 编写的。当我在字符串参数中有括号/括号 () 之类的字符时,UTF-8 编码器不会对它们进行编码,而 API 主机将它们编码为 %28 和 %29 并且我得到不正确的响应。有什么建议可以解决这个问题吗? API在文档中有如下参考docs.oracle.com/javase/1.5.0/docs/api/java/net/URLEncoder.html 你可以看看这个:***.com/questions/846487/…【参考方案3】:

Uri.EscapeDataString 将使用不符合 RFC 1738 的 Uri 标准转换字符串。

RFC 1738 是旧的 URL 标准。 我通过使用FormUrlEncodedContent 完成了它:

data = new List<KeyValuePair<string, string>>();
data.Add(new KeyValuePair<string, string>("key", "value"));

var payloadBody = await new FormUrlEncodedContent(data).ReadAsStringAsync();

如果您不需要编码的 URL body,您可能需要使用键/值 f.e 来欺骗 arround。让值为空。

【讨论】:

以上是关于如何对URL字符串进行百分号编码的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 python 请求对我的 URL 进行百分比编码?

Http请求url参数字符集

我来教你如何将URL进行编码和解码

如何解决Http请求参数中加号变空格问题

HTTP与会话管理

如何将Wikipedia的Unicode编码转成百分号编码