对接第三方OCR服务开发笔记
在最近的工作中,有对接第三方OCR服务的需求,经过一番捣鼓后,终于调试通了,在此记录下开发过程的心得体会。
需求北京说明
项目中用到OCR
识别功能,用于识别图片中的信息,解析后导入到系统。该功能由第三方以RestFul API
的形式提供,接口要求以POST
方式提供图片的base64
编码结果。
demo搭建
最开始,自己通过画图工具
,构造了一些图片,然后在 base64图片在线转换这里进行编码,获取右侧的字符串后,通过
curl -X POST -d"image=base64code" url
的方式测试,发现返回500错误
,通过询问第三方技术人员后发现是编码串的问题,通过和他们提供的测试串进行对比,发现以下区别:
网页工具生成的base64
字符串的格式为:
data:image/jpg;base64,XXX
前面的都是生成串的格式说明,后面的XXX
才是实际编码内容串。通过更换编码字符串后,继续测试,还是返回500
错误,这下又疑惑了。进一步沟通,发现那边是使用Postman
工具来对接口进行测试,顺便学习了Postman
工具,然后进行测试,并且与curl
命令行测试的结果进行对比,发现通过Postman
发送的POST
请求时,针对数据有以下四种传输类型:
- form-data: 将表单数据组织成key-value形式的一条消息,既可以上传键值对,也可以上传文件。
- x-www-form-urlencoded:将传输数据进行urlencoded编码,只可以上传键值对。
- raw:传递txt、json、xml、html等原始数据
- binary:只支持上传单个二进制数据
测试工具Postman
中,POST
发送的四种数据类型区别点此查看。
言回正传,调试不同,初步怀疑是Url
编码问题。查看curl
的自带的帮助,找到如下说明:
通过上面说明,可以知道:
- -d/--data:
-d
格式后面可以紧跟数据,也可以间隔一个空格。--data
后面必须间隔空格。默认文件内容格式为application/x-www-form-urlencoded
,表示传输内容已经经过url
编码,那么要求使用者需要自行编码后再传入。 - --data-ascii:同
--data
是一回事 - --data-binary:对上传数据不做任何处理,适合上传二进制数据,支持从文件中读取数据(@filename),保留回车和换行字符。
- --data-raw:同--data一样,但不会解析
@
字符。 - --data-urlencode: 对post的数据进行
url encoded
带着问题深入curl
带着以下两个问题,深入curl源码来了解。
-d
选项对应的处理源码在哪里?--data-urlencode
是哪个版本引入的,具体是如何处理?
curl
针对同类型选项,有一个映射缩写表:
{"d", "data", ARG_STRING},
{"dr", "data-raw", ARG_STRING},
{"da", "data-ascii", ARG_STRING},
{"db", "data-binary", ARG_STRING},
{"de", "data-urlencode", ARG_STRING},
由上表可见,--data
和 --data-urlencode
都是在命令行处理函数的 getparameter
中的case d
分支处理,--data-urlencode
在d
分支中的e
子分支继续处理。
tool_getparam.c
ParameterError getparameter(...)
{
// ... --data-urlencode
char letter = 'd';
char subletter = 'e';
char* nextarg; // 指向POST的数据指针 eg:value=123
switch(letter) {
case 'd':
{
if(subletter == 'e') {
const char *p = strchr(nextarg, '=');
size_t size = strlen(p);
char *enc = curl_easy_escape(NULL, postdata, (int)size);
}
// 将处理好的POST数据填入config
config->postfields = enc;
config->postfieldsize = size;
}
}
}
由上述截取的源码片段可知,--data-urlencode
使用curl_easy_escape
对post数据进行url
编码,而--data
则没有编码,此功能在7.18.0
版本中引入的。
特别提示:
使用curl的post功能时,如果POST的数据较长,不方便放在命令行中,可以将POSt数据存放在文件中,通过如下命令来发送:
curl --data-urlencode @file_path url
注意点:
- 当从文件中读取post内容时,请求数据中不在需要“=”号,如果有key的话,可以也要写到文件中.
- file_path可以用绝对路径,也可以用相对路径。当使用相对路径时,是相对于程序运行目录.
- file_path左右不需要加上引号
概要设计
通过前期的需求分析,此任务可划分为以下子任务:
- 加载图片
- 支持图片选择和拖拽
- 支持图片预览
- 图片有效性判断
- OCR图片解析
- 调用第三方API接口
- 解析过程的提示
- 异常情况处理
- 中途退出
- 解析超时
- 解析响应错误
- 处理正常解析结果
开发过程中的注意事项
该功能是在原有导入功能上新增的导入方式,解析输出结果要和其他导入方式相一致。
在发送POST请求时,由于之前是通过curl来发送,实现时,自然而然通过已有的curl组件来发送请求,初版提交后经同事审阅,需要使用该模块统一的数据请求通道,而不是通过curl来发送,理由有下:
- 走统一数据请求通道,数据在传输过程中是加密的,安全性有保证。
- 只需要传解析地址的路径即可,不需要传完整url,由后端统一处理测试环境和生产环境的差异。
- 有统一的日志记录和采集分析,如果是自己发送,则日志无法在中台留痕,不利于分析问题。
在新增功能时,时刻注意,不能因为优化重构,而影响原有功能。最好准备两份代码,一份开发新功能,另一份用于对比旧功能,保证同样的操作,新旧版本上现有功能不受影响。很多时候的重构优化,改多了会忘记现在这个情况是原有就有的,还是改动带来的优化,一定要注意,小步慢跑,稳步推进。
在开发完成后,提交之前,多看看自己写的代码,哪些变量和函数可以去掉,哪些地方可以减少拷贝操作,哪些命名还可以优化的。看完一片后,可以过一天,再继续看,总会有优化空间的。
提交到版本库中的配置,应该都是生产时的配置,不要将debug版本的配置提交上去。
小结
本文小结了对接第三方OCR服务过程中的心得体会,以飨读者。