用Visual C++实现SSL下Word文件发布

本文介绍了一种将Word文档转换为HTML并实现HTTPS安全上传的方法。通过使用ActiveX控件解析Word文档,并借助ZipUtils完成文件打包。解决了HTTP头格式问题及HTTPS上传时的证书验证难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

某网站项目后台管理要求实现一个功能,通过Word文件上传的方式实现文档发布功能。流程如下:用户选择一个word文档,系统自动识别出标题部分,并把余下的部分转化为HTML后作为正文发布。

原本的设计思路是把word上传到后台,由java对文档进行解析。一番周折后,发现java对word的支持并不理想,而且存在乱码问题。权衡再三,决定在客户端使用ActiveX控件。由控件实现对word文档的解析,并自动上传。

对word文档的解析亲自做起来才发现困难重重。通过#import或向导方式只能实现对某一版本的word文档的支持。word的版本从word97开始,分别经历了word2000、wordXP、word2002、word2003、以及当前的word2007。参考了大量的实现方案,发现微软的autowrap方案最为理想:http://support.microsoft.com/kb/216686/zh-cn。该方案把COM的IDispatch接口进行封装,通过模拟脚本调用的方式调用COM属性和方法,而且可以实现缺省参数调用,解决我这种问题相当优雅。

这样,通过_document的saveas方法,就可以把word转化为html。接下来的问题是,如何打包上传。第一个问题是如何打包,自然而然的想到zip。由于MFC不提供zip支持,而官方的zlib库无法实现文件夹压缩。以前的一个项目由于找不到解决方案,只能用rar的方式替代,缺点是必须带上rar的可执行文件。最终在CodeProject上找到一款非常好用的c++源码,Zip Utils:http://www.codeproject.com/KB/files/zip_utils.aspx。用法非常的简单,只需要包含一个zip.h即可。创建一个zip文件只需要以下几步:

HZIP hZip = CreateZip(m_pszZipPath, NULL); ZipAdd(hZip, sTempFilePath, sTempFileName); …… CloseZip(hZip);

最后一步便是文件的上传了。这好办,网上利用HTTP实现文件上传的代码很多,找来个能用的稍微改改,编译通过。用php写了个脚本,测试正常。

兴冲冲的发布。到了测试那里出现了问题,他用的是tomcat下的FileUpload类,竟然出现异常,而网上关于此异常竟然没有人给出解决方案。百思不得其解,但HTTP隐藏在平静的水面下,到底出了什么问题,只有分析HTTP头了。

安装了Fiddler2,编写了一个Servlet类,开始测试。为了做对比,用HTML的Form写了个上传表单,上传相同的文件,然后同控件上传的HTTP头进行对比。比较了半天,发现二者除了Agent之类信息之外,基本相同。都快绝望了,在UltraEdit中一行一行的盯,突然发现,IE产生的HTTP头在两个字段之间多了一个换行。带着怀疑的态度,我试着加了个换行……点击运行,竟然通过了。问题找到了,是我改的太狠,把代码中的应该有的/r/n给一起删了,原来还以为这是多余的。原来如此,这就是协议,来不得半点虚假。

于是打包,发布,客户测试都正常了,代码也扔一边去了。突然有一天,在讨论系统的安全性时,突然想到,客户后台都是通过HTTS+USB Key登录的,文件发布却是HTTP,这问题有点严重。

赶紧找到源码开始修改,却发现一下子束手无措,自己对SSL几乎是一知半解。通过MSDN知道,要实现HTTPS传输,只需要在MFC的OpenRequest中传入INTERNET_FLAG_SECURE参数。心想这么简单,代码一改赶紧测试,却发现SendRequest调用后直接返回异常:客户端无效授权。又去查MSDN,终于弄明白原因,写出以下代码解决问题:

CString strServer, strObject; DWORD dwServiceType, dwFlags; INTERNET_PORT nPort; AfxParseURL(serverPath, dwServiceType, strServer, strObject, nPort); dwFlags = dwServiceType == AFX_INET_SERVICE_HTTPS ? INTERNET_FLAG_SECURE : 0; pHttpConnection = Session.GetHttpConnection(strServer, nPort); pHTTP = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST, strObject, NULL, Session.GetContext(), NULL, NULL, dwFlags); //发送包头请求 pHTTP->AddRequestHeaders(MakeRequestHeaders(strHTTPBoundary)); bSuccess = FALSE; while (!bSuccess) { try { bSuccess = pHTTP->SendRequestEx(dwTotalRequestLength, HSR_SYNC | HSR_INITIATE); } catch (CInternetException* e) { DWORD dwError = e->m_dwError; switch (dwError) { case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED: case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: case ERROR_INTERNET_INCORRECT_PASSWORD: case ERROR_INTERNET_INVALID_CA: case ERROR_INTERNET_POST_IS_NON_SECURE: case ERROR_INTERNET_SEC_CERT_CN_INVALID: case ERROR_INTERNET_SEC_CERT_DATE_INVALID: // Return ERROR_SUCCESS regardless of clicking on OK or Cancel if (pHTTP->ErrorDlg(CWnd::FromHandle(GetDesktopWindow()), dwError, FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL) != ERROR_SUCCESS) { throw e; } break; default: throw e; } e->Delete(); } }

问题圆满解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值