WinForm截图OCR小项目的开发-瞥见知识的融会贯通

最近因为有个需要截图OCR的需求,再加上需要交一个C#大作业,就做了一个WinForm截图OCR小项目出来。
(不过后来发现QQ截图好像已经有这功能了?)

运行截图:

主窗口

截图处理窗口

弹出菜单

翻译窗口

历史日志

谈一谈挺有意思的一些知识点:

Http请求

Delegate委托回调

我封装了一个POST请求的函数:
需要下载一个Newtonsoft.Json用于处理响应的JSON数据
这种方式是使用了一个委托回调,类似于JavaScript中的回调函数,C#中叫Delegate回调

delegate void AfterRequest(JObject data);

class HttpUtil
{
    /// <summary>
    /// 发出POST请求
    /// </summary>
    /// <param name="url">请求的url</param>
    /// <param name="requestBody">url参数格式的字符串,如"key1=value1&key2=value2",需要经过urlencode处理</param>
    /// <param name="function">回调函数,data是一个json转换为的一个JObject对象</param>
    public static void PostAsync(String url, string requestBody, AfterRequest function)
    {
        try
        {
            string responseBody = null;
            HttpClient httpClient = new HttpClient();
            //StringContent content = new StringContent(requestBody,System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
            StringContent content = new StringContent(requestBody);

            content.Headers.ContentType =
                new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
            HttpResponseMessage response = null;
            response = httpClient.PostAsync(url, content).Result;
            response.EnsureSuccessStatusCode();
            if (response.IsSuccessStatusCode)
            {
                responseBody = response.Content.ReadAsStringAsync().Result;
            }
            JObject data = JObject.Parse(responseBody);
            function(data);
        }
        catch (Exception e)
        {
            Console.WriteLine("\nException Caught!");
            Console.WriteLine("Message :{0} ", e.Message);

        }

    }
}

Async/Await

实际上还有一种能使代码更清晰、简洁的方法,并且这种方法更受C#推荐:Async/Await

class HttpUtil
{
    /// <summary>
    /// 发出POST请求
    /// </summary>
    /// <param name="url">请求的url</param>
    /// <param name="requestBody">url参数格式的字符串,如"key1=value1&key2=value2",需要经过urlencode处理</param>
    public static async Task<JObject> PostAsync(String url, string requestBody)
    {
        try
        {
            string responseBody = null;
            HttpClient httpClient = new HttpClient();
            //StringContent content = new StringContent(requestBody,System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
            StringContent content = new StringContent(requestBody);

            content.Headers.ContentType =
                new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
            HttpResponseMessage response = null;
            response = await httpClient.PostAsync(url, content);
            response.EnsureSuccessStatusCode();
            if (response.IsSuccessStatusCode)
            {
                responseBody = await response.Content.ReadAsStringAsync();
            }

            JObject data = JObject.Parse(responseBody);
            return data;
        }
        catch (Exception e)
        {
            Console.WriteLine("\nException Caught!");
            Console.WriteLine("Message :{0} ", e.Message);
        }

        return null;
    }
}

使用这种方法,能避免回调地狱,让调用时代码不会多层嵌套。
甚至ES7也支持了这种方法,语法和C#类似。

原理:

函数执行时,一旦遇到await就会返回。等到触发的异步操作完成(并且调用栈清空),再接着执行函数体内后面的语句

实际上async/await只是个语法糖,内部执行顺序和回调函数并无区别。

API鉴权

因为做这个应用去调用了百度云和腾讯云提供的OCR api,恰巧发现两家的api鉴权机制正是目前主流验证方式之中具有代表性的两种。

百度云:Token

看看百度云的Token获取方法:

向授权服务地址https://aip.baidubce.com/oauth/2.0/token发送请求(推荐使用POST),并在URL中带上以下参数:

  • grant_type: 必须参数,固定为client_credentials;
  • client_id: 必须参数,应用的API Key;
  • client_secret: 必须参数,应用的Secret Key;

token验证方式就是给每个用户分配一套账号和密码(这里是client_id和client_secret),服务器能通过这套认证信息获取用户的权限,生成一个token字符串,保存在本地并返回给用户,用户请求api的时候就要带上这个token(可以是放在请求体或请求头中),服务器就能通过token验证用户的身份。

安全隐患: Token被劫持,伪造请求和篡改参数。

腾讯云:签名验证

可以看看腾讯云提供的计算签名的步骤:

  1. 将<key, value>请求参数对按key进行字典升序排序,得到有序的参数对列表N
  2. 将列表N中的参数对按URL键值对的格式拼接成字符串,得到字符串T(如:key1=value1&key2=value2),URL键值拼接过程value部分需要URL编码,URL编码算法用大写字母,例如%E8,而不是小写%e8
  3. 将应用密钥以app_key为键名,组成URL键值拼接到字符串T末尾,得到字符串S(如:key1=value1&key2=value2&app_key=密钥)
  4. 对字符串S进行MD5运算,将得到的MD5值所有字符转换成大写,得到接口请求签名

可以看出腾讯云的验证机制更为复杂,在计算签名的时候需要用到当前时间戳、一个随机字符串和用户的app_key,这样得到的签名每次请求的时候都是不同的,即使中间者劫持了签名也无法利用签名进行第二次重复请求,如果请求参数被篡改也能识别出。

Token和签名验证并不冲突,签名验证是在身份认证的基础上防止请求重放、参数篡改等攻击。百度云这种加密机制也可以使用某种密钥将带有token的参数字符串生成签名进行验证。

总结

要看到知识的融会贯通之处,学习JS相关的异步思想,后端的验证机制。要善于思考,以行促学。

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/winform%e6%88%aa%e5%9b%beocr%e5%b0%8f%e9%a1%b9%e7%9b%ae%e7%9a%84%e5%bc%80%e5%8f%91-%e7%9e%a5%e8%a7%81%e7%9f%a5%e8%af%86%e7%9a%84%e8%9e%8d%e4%bc%9a%e8%b4%af%e9%80%9a/