Blog icon indicating copy to clipboard operation
Blog copied to clipboard

用c#实现http服务器接受ajax请求,c#实现http客户端上传文件到远程服务器

Open abeet opened this issue 7 years ago • 0 comments

目的

在ZCMS中的文章编辑器是UEditor,我曾经在写了一个UEditor插件叫uploadLocalImage,作用是自动上传粘贴到文章编辑器中的本地图片到服务器。在从word文档中copy内容到编辑器中就可以自动上传其中的图片了。
在之前的笔记 https://github.com/abeet/Blog/issues/16 中有记录,在chrome插件中是通过NPAPI调用本地dll文件去读取本地文件,chrome45及以后的版本,加强了安全限制,禁止了NPAPI,所以chrome插件不能再访问本地文件了。 现在的思路是要求客户安装一个可执行程序,这个程序在本地启一个httpserver,编辑器中用js通过ajax和本地的httpserver通讯,通知这个本地服务上传本地硬盘上的文件到cms后台去。从而解决js不能访问本地文件的限制。而且这种方式与浏览器无关,不用为不同的浏览器开发插件了。

实现过程

  • 在github上搜索“http server”在c#语言里找项目,发现项目的代码量都比较多
  • 进.net的官网看看,https://www.asp.net/get-started
    在asp.net的官网发现asp .net core的入门特别简单,并且明显是用到了webserver的,于是安装.net core sdk,并试运行一个示例,成功
  • 查看示例源码,关键的一个组件是,实例化一个WebHostBuilder
  • 在百度搜索 WebHostBuilder,发现这篇文章,http://www.cnblogs.com/artech/p/net-core-hello-world.html 文中附有源码,将源码下下来,运行之
  • 第5个示例运行有误,开始认为是配置文件的版本不匹配,反复尝试,调整配置,花了两个小时,终于发现问题在于index.cshtml里head标签没有正常结束 期间还在github上找了一个简单示例,并根据这个示例尝试调整配置 https://github.com/SunKD/practice-portfolio/blob/master/Program.cs
  • 至此,在asp .net core里创建一个web服务器的过程基本了解。
  • 接下来是接受跨域的http请求
  • 在github搜索 "IApplicationBuilder app.UseMvc Access-Control-Allow-Origin" (事后发现应该先在百度搜索“.net core 跨域”,能更快速地定位到一个示例”https://www.cnblogs.com/qinghub/p/6398345.html “和”https://github.com/ingress2018/asptest/blob/master/src/AspNetCoreDemoApp/Startup.cs“)
  • 在众多代码中发现这样的写法 https://github.com/geruchvitaliy/Demo-AspNetCore-ApiEntityFramework/blob/fc22193f74032a5a0bbff04e4989e93cca6a1707/src/Api/Startup.cs https://github.com/SlingingCode/Healthy/blob/9fc16e7a6b11f10266c755eea0874e25faa6f784/Healthy.API/Startup.cs
services.AddCors (options => options.AddPolicy ("AllowAll", policy => policy.AllowAnyHeader ().AllowAnyMethod ().AllowAnyOrigin ().AllowCredentials ()));

经测试可跨域访问

  • 百度搜索“Mvc ActionResult” https://www.cnblogs.com/kissdodog/archive/2013/01/07/2850334.html 发现返回json数据的写法
public IActionResult status (string name) {
    var jsonObj = new {
        version = "1.0.0",
        status = "ok",
        error = "",
    };
    return Json (jsonObj);
}

public object status (string name) {
    var jsonObj = new {
        version = "1.0.0",
        status = "ok",
        error = "",
    };
    return jsonObj;
}
  • 写了例子,用postman测试成功
  • 再测试post请求,用postman测试,有错误“415 Unsupported MediaType”
  • 在google里搜索,发现原来要向后台提交数据必须是json格式 https://stackoverflow.com/questions/41597455/net-core-webapi-unable-to-post-data-with-postman-error-415-unsupported-me
  • 再多次尝试,终于能跨域发出post请求,并得到返回值
  • .net core里怎么处理post请求,在github里搜索一下即可,例于 https://github.com/tautvisv/HPTB/blob/master/HolidaysPlanningTool/src/HolidaysPlanningToolWeb/Controllers/ManageController.cs https://github.com/SlingingCode/Healthy/blob/master/Healthy.API/Controllers/PersonsController.cs
  • 至此服务端可与js交互了,在neditor.all.js里注释掉wordimage插件,
  • 在js控制台直接测试跨域提交post请求,js代码如下
$.ajax({
	url: 'http://localhost:10808/localupload',
	type: 'POST',
	contentType: 'application/json',
	data: JSON.stringify({
		"action":"localupload",
		"param1":"file:///C:\\Users\\abeet\\AppData\\Local\\Temp\\ksohtml\\wps58D8.tmp.jpg",
		"sendUrl":"http://localhost/api/catalogresources/9191/frontupload?siteID=14",
		"localSize":1024,
		"localExt":"gif,jpg,bmp,svg,png",
		"cookie":"IPCity=%E6%9C%AA%E7%9F%A5; ASPSESSIONIDQQARATRD=AEHBAMACAEIMHEHGPOGLDGEO"
	})
 }).then(function(res){
	console.log(res)
 },function(res){
	console.error(res)
 })
  • 引入自己的zuploadlocalimage插件,并调整逻辑,先将本地图片都换成一张固定的图片,成功
  • 接下来是要查找 .net core里http客户端相关的实例
  • github上找到这样一个类 https://github.com/justeat/httpclient-interception/blob/master/src/HttpClientInterception/HttpRequestInterceptionBuilder.cs
    感觉太复杂,.net core里应该会有提供更简单的方法。
  • 查 .netcore的api手册,没有找到与http通讯有关的内容,在microsofe全站搜索“HttpWebRequest”找到了 https://docs.microsoft.com/zh-cn/dotnet/api/system.net.httpwebrequest?view=netframework-4.7.2
    看来.net core里没有HttpWebRequest,.net framework里有 HttpWebRequest。 怎么办? 先试试google一下“asp.net core HttpWebRequest” 找了一篇文章 https://zhuanlan.zhihu.com/p/22764927 ,试试用它这个写法 看来只能用 WebRequest了, 参考一下 https://github.com/qinyuanpei/HttpServer/blob/master/HTTPServer/HTTPClient/Program.cs 的写法试试,向远程服务器请求内容成功。 接下来需要发送文件了。
  • 在github里搜索“WebRequest Method POST GetRequestStream Write multipart/form-data File” 找到一些参考如 https://github.com/xiongc169/20160331-Hs.web/blob/master/hs.web/hs.console/utility/upload/UploadUtility2.cs
  • 依照这个写各服务器发起请求,用PostMan发起一个请求
{
"action":"localupload",
"param1":"file:///C:\\Users\\abeet\\AppData\\Local\\Temp\\ksohtml\\wps7D7A.tmp.jpg",
"sendUrl":"http://localhost/api/catalogresources/9191/frontupload?siteID=14",
"localSize":1024,
"localExt":"gif,jpg,bmp,svg,png",
"cookie":"IPCity=%E6%9C%AA%E7%9F%A5; ASPSESSIONIDQQARATRD=AEHBAMACAEIMHEHGPOGLDGEO"
}

结果有错误,在java类里打断点跟踪后发现,其一要传递siteID和addUser,其二我们后台java方法限定了表单元素的name为file,调整后,顺利地通过c#上传了临时文件夹下的图片。

  • 至此终于可以在cms后台的编辑器里正式测试了。
  • 在js里对预览路径进行处理后就ok了
  • 生成exe文件,在项目根目录执行 dotnet build -r win10-x64
  • 然后是要注册为服务,在百度里搜索“C# 注册为windows服务”找到的文章有
    https://www.cnblogs.com/sorex/archive/2012/05/16/2502001.html
    需要特别的写法,还需要使用installutil.exe 去安装,这个安装文件客户的机器上未必会有
  • 在github里搜索 “windows service”,发现有一个项目的星比较多
    https://github.com/kohsuke/winsw
    winsw 可以将Windows上的任何一个程序注册为服务
  • 下载winsw,并装备好配置文件,然后将winsw,zvingtools.exe及所有依赖,一起打包为自解压程序,解压到program files目录,并执行
winsw uninstall
winsw install
winsw start
  • 试执行这个自解压程序,在没有使用管理员身份运行的情况下,服务也启动起来了。 使用PostMan尝试连接 http://localhost:10808/ 成功!
  • 耶,到此目标初步达成——用c#实现一个http服务接受ajax请求,c#实现http客户端上传文件到远程服务器

abeet avatar Apr 16 '18 12:04 abeet