【问题标题】:How to find out if string has already been URL encoded?如何找出字符串是否已经被 URL 编码?
【发布时间】:2011-01-18 17:00:45
【问题描述】:

如何检查字符串是否已经编码?

例如,如果我编码TEST==,我得到TEST%3D%3D。如果我再次编码最后一个字符串,我得到TEST%253D%253D,如果它已经编码,我必须在这样做之前知道......

我已经保存了编码参数,我需要搜索它们。我不知道输入参数,它们将被编码或不编码,所以我必须知道在搜索之前是否必须对它们进行编码或解码。

【问题讨论】:

  • 同意。您接受了错误的答案。
  • import java.net.URI String url = "www.demo.demo/demo 文件未编码.jpg" boolean isEncoded = true;尝试 { URI x = new URI(url) } catch(Exception ex) { isEncoded = false; }

标签: java utf-8 url-encoding


【解决方案1】:

解码,与原始文件进行比较。如果确实不同,则对原始内容进行编码。如果没有差异,则原始文件未编码。但它仍然没有说明新解码的版本是否仍未编码。递归的好任务。

我希望不能用 urlencode 写一个 quine,否则这个算法会卡住。

例外:当字符串包含“+”字符时,即使字符串未经过 url 编码,url 解码器也会将其替换为空格

【讨论】:

  • 好吧,除了“足够好”就足够了;如果 0.01% 的用户真的不希望该程序运行,那么它对他们不起作用。有时,额外的、极端的条款根本不值得付出努力和开销。
  • 如果您的字符串包含 Windows 变量名称,如 %DESCRIPTION% 解码为 ÞSCRIPTION%%ABOUT% 变为 «OUT%,则会失败。
  • @SF。 :如果初始未编码的字符串在中间包含一个 + 字符,这将失败。解码后的字符串将包含一个空格字符,并且不相等。更好的方法是比较长度。如果原始字符串大于解码字符串,则原始字符串被编码。
  • 如果原始字符串包含加号则不起作用。您对其进行解码,与原始文件进行比较,并且字符串不同。 + 已替换为空格。你最终没有编码它,即使你应该。
  • 这是破旧的。当字符串包含“+”字符时,即使字符串未经过 url 编码,url 解码器也会用空格替换它。见docs.oracle.com/javase/6/docs/api/java/net/URLDecoder.html
【解决方案2】:

使用正则表达式检查您的字符串是否包含非法字符(即在 URL 编码的字符串中找不到的字符,如空格)。

【讨论】:

  • 我没有这样做,但这就是解决方案。
  • 那么您将如何区分 hello%20worldinterest20%growth ?第一个是有效的 urlencoded 字符串,另一个是必须转义且不会产生有效 unescape 的字符串。
  • 检查非法字符不包括百分号,因为它不是非法的,它只是被转义了。当您检查百分号时,如果后面跟着“25”,您可能有一个 URI 编码字符串。这仅在您知道您的输入未编码或完全编码 1 次并且输入不自然包含 URI 编码生成的序列时才有效。
  • 不幸的是,这不是解决方案。我将 URL 作为 url 加密字符串传递,所以我做了一个 REFind(':', str) 并返回 6 (https:) 无论字符串是否加密。
  • 如果一个字符串包含无效的字符,你可以证明它没有被编码,但是如果它只包含有效的字符和百分号,那并不能证明它是被编码的。这是不可知的。因此,这可能是一项切实可行的检查。
【解决方案3】:

尝试解码网址。如果生成的字符串比原始字符串短,那么原始 URL 已经被编码,否则您可以安全地对其进行编码(或者未编码,或者甚至发布编码后 url 保持原样,因此再次编码不会导致错误的 url )。以下是示例伪(受 ruby​​ 启发)代码:

# Returns encoded URL for any given URL after determining whether it is already encoded or not
    def escape(url)
      unescaped_url = URI.unescape(url)
      if (unescaped_url.length < url.length)
        return url
      else
        return URI.escape(url)
      end
    end

【讨论】:

  • 如果 url 以 ' '(空格) 被 '+' 替换的方式编码,这将不起作用,因为长度保持不变
  • 最好将您的 URL 编码为 %20。此处描述了优点:stackoverflow.com/a/2678602/762747 如果这不可能,那么您可以检查 ? 之后的 + 符号,如果找到,则 URL 已经编码,您可以按原样返回。这只是对上述代码的额外检查,具体取决于您的用例。
【解决方案4】:

您无法确定,除非您的字符串符合特定模式,或者您跟踪您的字符串。正如您自己指出的,编码的字符串也可以编码,因此您不能通过查看字符串本身来 100% 确定。

【讨论】:

    【解决方案5】:

    软件方面的 Joel 曾经有过解决方案 - http://www.joelonsoftware.com/articles/Wrong.html
    或者您可以在字符串中添加一些前缀。

    【讨论】:

    • 也许更好:一个包装器类型 struct QuotedString {char *str;} 传递,然后你可以显式地(并且可以发现地)弄乱它的内部。
    【解决方案6】:

    检查您的 URL 是否有可疑字符[1]。 候选人名单:

    WHITE_SPACE ,", &lt; , &gt; , { , } , | , \ , ^ , ~ , [ , ] , . 和`

    我用:

    private static boolean isAlreadyEncoded(String passedUrl) {
            boolean isEncoded = true;
            if (passedUrl.matches(".*[\\ \"\\<\\>\\{\\}|\\\\^~\\[\\]].*")) {
                    isEncoded = false;
            }
            return isEncoded;
    }
    

    对于我继续进行的实际编码:

    https://stackoverflow.com/a/49796882/1485527

    注意:即使您的网址不包含您可能想要应用的不安全字符,例如Punnycode 编码到主机名。所以还有很多空间可以进行额外的检查。


    [1] 候选人名单可在第 2 页URL spec 的“不安全”部分找到。 据我了解,编码检查中应省略“%”或“#”,因为这些字符也可能出现在编码后的 URL 中。

    【讨论】:

      【解决方案7】:

      使用 Spring UriComponentsBuilder:

      import java.net.URI;
      import org.springframework.web.util.UriComponentsBuilder;
      
      private URI getProperlyEncodedUri(String uriString) {
          try {
              return URI.create(uriString);
          } catch (IllegalArgumentException e) {
              return UriComponentsBuilder.fromUriString(uriString).build().toUri();
          }
      }
      

      【讨论】:

      • 感谢您的回答,确认它在 Java 中使用 spring 可以正常工作
      【解决方案8】:

      为了避免编码两次并产生错误(正如 OP 所说),我们取消引用而不是再次引用,在 Python 中这将是:

      import urllib.parse
      urllib.parse.unquote(str)
      urllib.parse.quote(str)
      

      【讨论】:

      • OP 用java 标签标记了问题,而不是python...
      • @cdalxndr,你有很多空闲时间吧?我分享了我的概念性答案,并给出了一个 Python 示例,该示例也可以用 Java 实现。
      • 考虑一下如果每个人都用他们想要的任何编程语言来回答会发生什么......那么挖掘你需要的答案变得越来越困难。除了 python 示例之外,您至少应该提供一个 java 示例。 java中的urllib.parse通讯员是什么?
      • 如果没有帮助,它会被版主删除。
      【解决方案9】:

      如果您想确保字符串编码正确(如果需要编码) - 只需再次对其进行解码和编码。

      元代码:

      100%_correctly_encoded_string = encode(decode(input_string))
      

      已经编码的字符串将保持不变。未编码的字符串将被编码。仅包含 url 允许字符的字符串也将保持不变。

      【讨论】:

      • 不。使用其中包含“%s”的未编码字符串对其进行测试。由于 InvalidArgumentException 是由无效的“%xy”引起的,其中 xy 应该是十六进制数字,异常将使这样设计的代码无法执行。与已接受的答案相同的问题,并且会引发其他糟糕的设计缺陷,例如忽略未知的异常类型。
      【解决方案10】:

      根据规范 (https://www.rfc-editor.org/rfc/rfc3986),所有网址必须以方案开头,后跟:

      由于需要冒号作为方案和 URI 其余部分之间的分隔符,因此任何包含冒号的字符串都不会被编码。

      (这假设您不会得到一个不完整的没有方案的 URI。)

      所以你可以测试字符串是否包含冒号,如果没有,则urldecode它,如果该字符串包含冒号,则原始字符串是url编码的,如果没有,检查字符串是否不同,如果是,再次urldecode如果不是,则它不是有效的 URI。

      如果你知道你可以期待什么方案,你可以使这个循环更简单。

      【讨论】:

        【解决方案11】:

        感谢this answer,我编写了一个函数(JS 语言),它只用encodeURI 对 URL 进行一次编码,因此您可以调用它来确保只编码一次并且您不需要知道 URL 是否是已经编码了。

        ES6:

        var getUrlEncoded = sURL => {
            if (decodeURI(sURL) === sURL) return encodeURI(sURL)
            return getUrlEncoded(decodeURI(sURL))
        }
        

        ES6 之前的:

        var getUrlEncoded = function(sURL) {
            if (decodeURI(sURL) === sURL) return encodeURI(sURL)
            return getUrlEncoded(decodeURI(sURL))
        }
        

        这里有一些测试,所以你可以看到 URL 只被编码过一次

        getUrlEncoded("https://example.com/media/Screenshot27 UI Home.jpg")
        //"https://example.com/media/Screenshot27%20UI%20Home.jpg"
        getUrlEncoded(encodeURI("https://example.com/media/Screenshot27 UI Home.jpg"))
        //"https://example.com/media/Screenshot27%20UI%20Home.jpg"
        getUrlEncoded(encodeURI(encodeURI("https://example.com/media/Screenshot27 UI Home.jpg")))
        //"https://example.com/media/Screenshot27%20UI%20Home.jpg"
        getUrlEncoded(decodeURI("https://example.com/media/Screenshot27 UI Home.jpg"))
        //"https://example.com/media/Screenshot27%20UI%20Home.jpg"
        getUrlEncoded(decodeURI(decodeURI("https://example.com/media/Screenshot27 UI Home.jpg")))
        //"https://example.com/media/Screenshot27%20UI%20Home.jpg"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-14
          • 2012-08-28
          • 1970-01-01
          • 1970-01-01
          • 2013-07-08
          • 1970-01-01
          相关资源
          最近更新 更多