• ASP.NET Core – 操作 Uri 和 Query


    前言

    以前就有写过了 Asp.net core 学习笔记 (操作 URL 和 Query), 但很乱, 这篇作为整理.

    Uri 介绍

    结构:

    [Scheme]://[Host]:[Port][/Path][?Query][#Fragment]

    对应:

    [https:]//[www.stooges.com.my]:[443][/blog/air%20service][?title=my%20title][#my-id]

    path 和 query 都需要 encode. 

    %20 就是空格 (space) 的 encode.

    ASP.NET Core 有 2 个方法用来 encode 它们

    public static string EncodeQuery(string keyOrValue)
    {
        // 从 QueryBuilder 源码抄来的
        return UrlEncoder.Default.Encode(keyOrValue);
    }
    public static string EncodePath(PathString path)
    {
        // 从 UriHelper.BuildAbsolute 源码抄来的
        return path.ToString();
    }

    Read URI (from request)

    在 读写 Request / Response 有提到过如何获取 request URI. 这里补充一些细节.

    1. Fragment 是无法从 request URI 获取的. 因为那个是 for client side 的.

    2. HostString 对象

    HostString hostString = HttpContext.Request.Host;
    string host = HttpContext.Request.Host.Host; // www.stooges.com.my
    int? port = HttpContext.Request.Host.Port; // 44300
    string hostAndPort = HttpContext.Request.Host.ToString(); // www.stooges.com.my:44300

    3. PathString 对象

    PathString pathString = HttpContext.Request.Path;
    string? path = pathString.Value; // "/contact me/dada"
    string path1 = pathString.ToString(); // "/contact%20me/dada"

    注意: 1 个有 decode 1 个没有 decode

    4. QueryString 对象

    和 PathString 差不多接口

    QueryString queryString = HttpContext.Request.QueryString;
    string query1 = queryString.ToString(); // "?page=%201&value=xx"
    string? query2 = queryString.Value; // "?page=%201&value=xx"

    注意: 2 个都是没有 decode 的哦,

    5. Query 对象

    QueryString 没有太多的作用, 真的想方便的话用 Query

    if (HttpContext.Request.Query.TryGetValue("page", out StringValues values))
    {
        // ?page=1&page=%202
        string value1 = values.ElementAt(0); // "1"
        string value2 = values.ElementAt(1); // " 2"
        var values3 = values.ToString(); // "1, 2"
    }

    注意: 它的 decode 好的哦. 当有重复 key 的时候, value 会放到 values 里面.

    也可以遍历它. 

    IEnumerable<KeyValuePair<string, StringValues>> keyValuePairs = HttpContext.Request.Query;
    foreach (var kv in keyValuePairs)
    {
        string key = kv.Key;
        var value = kv.Value.ToString(); // "1, 2"
    }

    注意: key 是不会重复的, 因为已经合并到 values 里的.

    6. GetDisplayUrl

    它是 extension Microsoft.AspNetCore.Http.Extensions, 获取当前完整路径.

    注意:

    它不包含 #Fragment, Path 会 decode, Query 不会 decode. 和上面的逻辑是一致的.

    如果想获取没有 decode 的 URL, 可以调用 GetEncodedUrl()

    Read URI (from string)

    var uri = new Uri("https://www.stooges.com.my/about%20us/detail?page=1#my-id");
    
    string scheme = uri.Scheme; // https
    string host = uri.Host; // www.stooges.com.my
    int port = uri.Port; // 443
    string path = uri.LocalPath; // /about us/detail (decoded)
    string absolutePath = uri.AbsolutePath; // "/about%20us/detail"
    string query = uri.Query; // ?page=1
    string fragment = uri.Fragment; // #my-id
    string pathAndQuery = uri.PathAndQuery; // "/about%20us/detail?page=1"

    几个点注意:

    1. Frament 可以拿到

    2. Path, Query, Fragment 分别 starts with "/", "?", "#"

    3. Query 是没有 decode 的

    4. LocalPath 有 decode, AbsolutePath 没有 decode, PathAndQuery 没有 decode

    5. 除了 port 全部返回都是 string 而不是 HostString, PathString, QueryString 这类的.

    比起 read URI from request, new Uri 简单多了. 它的 Query 最好交给 QueryHelper 处理哦.

    QueryHelpers

    Request.Query 很方便, 但是 Uri 没有这些. 所以需要 QueryHelpers 帮忙

    var uri = new Uri("https://www.stooges.com.my?page=1&page=%202");
    
    string queryString = uri.Query; // ?page=1&page=%202
    
    Dictionary<string, StringValues> query = QueryHelpers.ParseQuery(queryString);
    var value1 = query["page"].ElementAt(0); // "1"
    var value2 = query["page"].ElementAt(1); // " 2" decoded
    var value3 = query["page"].ToString(); // "1, 2"
    
    foreach (KeyValuePair<string, StringValues> kv in query)
    {
        string key = kv.Key; // page
        StringValues values = kv.Value; 
    }

    用起来很简单, 把 Uri.Query 传给 QueryHelpers 就可以了, 基本上就有了 Request.Query 的所有能力了.

    返回字典, 字典继承了 IEnumerable<KeyValuePair<string, StringValues>> 所以也可以遍历拿到 KeyValuePair.

    QueryBuilder

    介绍完 read, 现在介绍 build. 先从简单的 build query 开始.

    var queryBuilder = new QueryBuilder();
    queryBuilder.Add("page", "1");
    queryBuilder.Add("page", " 2");
    queryBuilder.Add("value", "abc");
    
    QueryString queryString = queryBuilder.ToQueryString();
    
    var queryString1 = queryString.Value; // "?page=1&page=%202&value=abc"
    var queryString2 = queryString.ToString(); // "?page=1&page=%202&value=abc"

    添加, 最后 ToQueryString 就可以了,

    1. value 不需要自己 encode

    2. 不管是 queryString.Value 还是 .ToString() 都是 encoded 的 (QueryString 都是 encoded 的上面介绍 read 的时候也有提到)

    QueryBuilder 初始化还支持 KeyValuePairs 哦

    var keyValuePairs = new Dictionary<string, StringValues>
    {
        ["page"] = new StringValues(new[] { "1", " 2" }),
        ["value"] = "abc"
    };
    var queryBuilder = new QueryBuilder(keyValuePairs);

    这样和上面的例子是等价的效果.

    UriBuilder

    var uriBuilder = new UriBuilder();
    uriBuilder.Scheme = "https";
    uriBuilder.Host = "www.stooges.com.my";
    uriBuilder.Port = 443; // 通常是不需要放的, https 自动是 443, http 自动是 80
    uriBuilder.Path = "/blog/air service"; // better starts with /, make it consistency
    uriBuilder.Query = "?page=1"; // better starts with ?, make it consistency
    uriBuilder.Fragment = "#my-id"; // better starts with #, make it consistency
    var url = uriBuilder.ToString(); // "https://www.stooges.com.my:443/blog/air%20service?page=1#my-id"

    1. Path 不需要 encode

    2. Query 需要 encode, 最好是通过 QueryBuilder 制作

    3. Path, Query, Fragment 最好 starts with "/", "?", "#" 因为 Read 的时候是有的, 让它们一致性.

    总结

    1. 通过 Request 获取 information 比较 Uri 方便, 尤其是 Query 的部分, 因为它有封装.

    2. 可以借助 QueryHelpers 来读取 Query, Request.Query 内部也是靠它的.

    3. Path 都是自动 encode, decode 的.

    4. Query string 需要 Builder, Helpers 来做帮助 encode, decode.

  • 相关阅读:
    SolrQuery的使用
    solr服务(搜索服务)
    linux下安装jdk
    Gartner:2018人工智能技术成熟度曲线
    Gartner 2018新技术成熟度曲线
    Market Guide for AIOps Platforms
    OpenStack的基本概念与架构图
    OpenStack OVS GRE/VXLAN
    VLAN,GRE,VXLAN
    企鹅智库发布《2019-2020中国互联网趋势报告》
  • 原文地址:https://www.cnblogs.com/keatkeat/p/16087644.html
Copyright © 2020-2023  润新知