C#向JAVA发送form-data文件问题处理方案
前言
和上一篇文章一样,.NET 和 JAVA之间的接口请求又遇到了新问题
我们有一个用来接收文件的接口,外部把文件流、文件名、目录,传进来,我们系统把生成的附件ID反回去,接口为POST-form-data格式
我用POSTMAN调用没有问题,就把文档写好发出去了,结果.NET开发的兄弟就又进行不下去了
问题现象
一模一样的参数,POSTMAN里请求正常,C#请求就返回空,翻了一下我们的日志,
NullPointerException 这。。。也不知道是哪抛出来的,本来就是原有的接口,逻辑一大堆,只看日志也看不出个所以然。
而且客户的环境我还没办法远程debug,我本地环境又没办法让对方开发调。
于是乎我和他们远程会议一点点猜他代码的问题,该加的参数都加了,找不出来哪有毛病。
处理过程
最后本着能让他们改,我自己就不动的原则,我开始研究起来了C#,之前基本没怎么接触过,从准备环境开始。。。
详细的环境准备过程请看:
//TODO C#环境准备
因为本来就不怎么会写么,况且POSTMAN能调通,于是准备直接用POSTMAN生成的代码来测,就得到了这个:
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:8080/api/doc/upload/uploadFile2Doc");
request.Headers.Add("appid", "CRM");
request.Headers.Add("token", "a3c6e10f-2269-4851-a3e4-3bb7bb1df183");
request.Headers.Add("userid", "EGqrxYColwBVopfkbVn/jUI7n9fPkRvcwnMh5LbNLuCkykywI902H3F98wvwlY8CWeHKXuiwLR8DmsCmupjcD1x79kMsNVkJOiq5N4y4Dj+CaFcelvdL+Nypgho3Sj4dPc/hRkbdXnvf4iAh8LR7v22pQOKuHm8I7ZclLID87JGKlsEs+X64CtJEJtTGh6js4PDBR5zWFB8NwxmcJHq4M26RNWeZVp7Tz93W5qv3WvgROUuuK7cla5gu8GgwqSJAQlti2VuNJpLIgTRNsB7UQeYCrGYNOTAU0JzDhAi+A3t7hA4eoWHb0+na/SLgR6sQrGzLk4KpO6rkU7PVCrHkjg==");
var content = new MultipartFormDataContent();
content.Add(new StreamContent(File.OpenRead("/C:/Users/13064/工作/测试文件/测试表格.xlsx")), "file", "/C:/Users/13064/工作/测试文件/测试表格.xlsx");
content.Add(new StringContent("测试表格.xlsx""), "name");
request.Content = content;
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());
不出所料,还是返回了个{}
不过好在是自己的环境,Debug,启动!
一层一层的找,发现这个NullPointerException 是因为拿到的file为null,于是我天真的揣测是不是header没有指定类型的问题
于是天真的加上了
content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data")
果不其然,报错变了
Separation boundary was not specified
这是个什么东西,之前没见过,简单搜了一下,表明 multipart/form-data 请求中缺少边界(boundary)信息
然后文档里还写 :MultipartFormDataContent确保你没有在请求中手动设置 Content-Type,因为 C# 会自动添加边界
好吧,画蛇添足了属于是
继续从JAVA侧入手吧,看看为什么file为null,继续深入,发现file不是没拿到,而是到file这个参数的时候出问题了,但是异常并没有抛出
直接在里面catch掉之后return了个null
java.lang.RuntimeException: >>>>Xss(NoPass),invalidChar in params:--->referer:null path:/api/doc/upload/uploadFile2Doc param:=?utf-8?B?5rWL6K+V6KGo5qC8Lnhsc3g=?= rule=(the value is too big!(1000000)) paramValue:PK
值超长?其实这会就该想到为什么了,但是没反应过来,新建了个TXT传,心想肯定不会超长了吧,结果倒是没超长,但是file还是没拿到
仔细看了下,发现file参数被当作了个普通param来处理的,怪不得文件大一点就超长了
既然这种请求方式JAVA侧拿不到正确的参数类型,那就换一种,于是就从POSTMAN又得到了这段代码
var options = new RestClientOptions("http://localhost:8080")
{
MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("/api/doc/upload/uploadFile2Doc", Method.Post);
request.AddHeader("appid", "CRM");
request.AddHeader("token", "a3c6e10f-2269-4851-a3e4-3bb7bb1df183");
request.AddHeader("userid", "EGqrxYColwBVopfkbVn/jUI7n9fPkRvcwnMh5LbNLuCkykywI902H3F98wvwlY8CWeHKXuiwLR8DmsCmupjcD1x79kMsNVkJOiq5N4y4Dj+CaFcelvdL+Nypgho3Sj4dPc/hRkbdXnvf4iAh8LR7v22pQOKuHm8I7ZclLID87JGKlsEs+X64CtJEJtTGh6js4PDBR5zWFB8NwxmcJHq4M26RNWeZVp7Tz93W5qv3WvgROUuuK7cla5gu8GgwqSJAQlti2VuNJpLIgTRNsB7UQeYCrGYNOTAU0JzDhAi+A3t7hA4eoWHb0+na/SLgR6sQrGzLk4KpO6rkU7PVCrHkjg==");
request.AddHeader("Cookie", "ecology_JSessionid=aaah7nfm2JXcVfjSBTajz; languageidweaver=7; loginidweaver=1");
request.AlwaysMultipartFormData = true;
request.AddFile("file", "/C:/Users/13064/工作/测试文件/测试表格.xlsx");
request.AddParameter("name", "测试表格.xlsx");
RestResponse response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);
调用一下,发现这次JAVA这边连debug都没进,而且C#这边也什么都没打出来
简单研究了一下RestResponse的用法
加上了如下代码
if (response.IsSuccessful)
{
Console.WriteLine("请求成功:");
Console.WriteLine(response.Content);
}
else
{
Console.WriteLine("请求失败:");
Console.WriteLine($"状态码: {response.StatusCode}");
Console.WriteLine($"错误信息: {response.ErrorMessage}");
Console.WriteLine($"响应内容: {response.Content}");
}
状态码: NotAcceptable
继续添加
request.AddHeader("Accept", "*/*");
再看JAVA侧,终于file是个文件了,回看C#也已经正确拿到了返回数据
完整代码
为了方便扔给那边的兄弟做测试,简单优化了下
using RestSharp;
using Newtonsoft.Json.Linq;
string uri = "http://127.0.0.1:8080";
var json = await GetToken();
var jsonObject = JObject.Parse(json);
string token = (string)jsonObject["token"];
var options = new RestClientOptions(uri)
{
MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("/api/doc/upload/uploadFile2Doc", Method.Post);
request.AddHeader("appid", "CRM");
request.AddHeader("token", token);
request.AddHeader("userid", "zOumGpDpL6azXvv/DBS/V3wxmqRxkJg3G1iI20RKtks6PcPTEykqJBAgwze9xT4DSUnaMQdYev3BiAFEX1DpsFoDYKe5LYuXf8h0o/KD86HE4DqzlfrNhwr4bFrbT+YZrONxc+hzx8m1QsqdwZMosrPnSbM0xQEwwMr/TAg3JRQmgDEa+OggqYupEaVfVIJklJEdtX6g2Dfor+WX79aCnKphZxp/N62zi/w6iBusSbwtAADN8Ind61YBZq/+yoi9E/FlkENRTv3tTwNAA59CHYbYZnpvIEW7XddefPTx9JVWtPN40kueNBLTdbsz41HuHOIcMFdaEGTTnA6hYUWllg==");
request.AddHeader("Accept", "*/*");
request.AlwaysMultipartFormData = true;
request.AddFile("file", "./t.txt");
request.AddParameter("name", "t.txt");
RestResponse response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
Console.WriteLine("请求成功:");
Console.WriteLine(response.Content);
}
else
{
Console.WriteLine("请求失败:");
Console.WriteLine($"状态码: {response.StatusCode}");
Console.WriteLine($"错误信息: {response.ErrorMessage}");
Console.WriteLine($"响应内容: {response.Content}");
}
async Task<string> GetToken()
{
var options = new RestClientOptions(uri)
{
MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("/api/ec/dev/auth/applytoken", Method.Post);
request.AddHeader("appid", "CRM");
request.AddHeader("secret", "hqHTV4Bf0/AN74M+FXxWs3v2GxxYrQwGoE+ioUOkFttFAFMGAR55JAzDeUkxN5MUwkHy+ovu2Fh2NtEoQh396dIAkdUdHiqzvrxHAIaHPfNrcUtAFVkcqRAKOsVLBVSAR7tMTxw5KkEqYI4mV/pMZeZB5tKK08nUFOi5u06xUwB8AS/jo8CYfuAFJ8xAJWld6bjGnNW6nJXWXam1lbMsD9RUZWJ/RHSzrISDCmNauG+ejpNuB8A4uyAaY7kEIx723ZU2HkczExfQXxwtEjCwS8elj8bQp39j+g8bYlL2O6fP2GDlWhYhzorGgzNc6MYBZFaQ2vDgP3KCP9NX9JlhSQ==");
request.AddHeader("Accept", "*/*");
RestResponse response = await client.ExecuteAsync(request);
return response.Content;
}
PS:C#语法确实比JAVA写起来方便,psvm都没有就能用,而且比较有意思的是编译之后直接就能生成exe,之前我那JAVA写的东西想给别人直接双击启动 还得自己写bat,或者用exe4j,后面可以好好研究研究。
C#向JAVA发送form-data文件问题处理方案的更多相关文章
- fetch发送Form Data请求并携带cookie
今天我们来说说如何fetch发送Form Data请求并携带cookie,直接进入正题好吧,别问我今天为啥不在开始吹两句了,累到一句牛逼不想吹...... 步骤1: 设置头部,"Conten ...
- VUE axios 发送 Form Data 格式数据请求
axios 默认是 Payload 格式数据请求,但有时候后端接收参数要求必须是 Form Data 格式的,所以我们就得进行转换.Payload 和 Form Data 的主要设置是根据请求头的 C ...
- python 处理form/data文件上传
处理multipart/form-data 的java serverlet请求接口通过python实现 记住不要在头加:"Content-Type":"multipart ...
- springMVC中对HTTP请求form data和request payload两种数据发送块的后台接收方式
最近在做项目中发现,前台提交数据时,如果通过form表单提交和ajax发送json时,springMVC后台接收不能都通过@ModelAttribute方式处理,经过一番查找后,ajax发送json请 ...
- Socket通讯-C#客户端与Java服务端通讯(发送消息和文件)
设计思路 使用websocket通信,客户端采用C#开发界面,服务端使用Java开发,最终实现Java服务端向C#客户端发送消息和文件,C#客户端实现语音广播的功能. Java服务端设计 packag ...
- [整理]Ajax Post请求下的Form Data和Request Payload
Ajax Post请求下的Form Data和Request Payload 通常情况下,我们通过Post提交表单,以键值对的形式存储在请求体中.此时的reqeuest headers会有Conten ...
- html5 file upload and form data by ajax
html5 file upload and form data by ajax 最近接了一个小活,在短时间内实现一个活动报名页面,其中遇到了文件上传. 我预期的效果是一次ajax post请求,然后在 ...
- form data和request payload的区别
HTML <form> 标签的 enctype 属性 在下面的例子中,表单数据会在未编码的情况下进行发送: <form action="form_action.asp&qu ...
- Web 前沿——HTML5 Form Data 对象的使用
XMLHttpRequest Level 2 添加了一个新的接口——FormData.利用 FormData 对象,我们可以通过 JavaScript 用一些键值对来模拟一系列表单控件,我们还可以使用 ...
- HTTP请求中的form data和request payload的区别
HTML <form> 标签的 enctype 属性 在下面的例子中,表单数据会在未编码的情况下进行发送: <form action="form_action.asp&qu ...
随机推荐
- C++面试题整理 2
8. C++11新特性又哪些 自动类型推导auto,智能指指针(share_ptr,unique_ptr等),for循环简化,线程相关的(std::thread/std::mutex),空指针null ...
- Java发展到现在,哪些技术可以放弃了?
各位好啊,我是会编程的蜗牛,作为java开发者,对于各类java开发技术.开发框架肯定是多少都要了解和知道的. 但是作为已经发展了几十年的java开发生态,各类技术层出不穷,有的新技术新框架已经对旧技 ...
- 暑假集训CSP提高模拟4
A.White and Black 暴力的 \(O(nq)\) 做法比较显然,因为对于根节点来说,只有它自己可以改变自己的颜色,因此如果它是黑色则一定需要更改自己,同时把更改传下去(应该没有那种每次真 ...
- C++20中对于并发方面的进步
在当今的编程世界中,并发处理能力变得越来越重要.C++20 在并发方面带来了一些进步,使开发者能够更高效.更安全地编写多线程应用程序.这些进步主要包括: 作用域线程(Scoped Threads) 停 ...
- argmax经过sigmoid和不经过sigmoid区别
起因 今天和同组讨论了一下网络输出时,在torch.argmax之前经过torch.sigmoid和不经过sigmoid的区别. 主要起因是实验结果图像不同 图1 不经过sigmoid 图2 经过si ...
- WebAssembly C++开发环境搭建
WebAssembly 开发环境搭建 简介 WebAssembly 是一种新的编码方式,可以在现代的网络浏览器中运行 - 它是一种低级的类汇编语言,具有紧凑的二进制格式,可以接近原生的性能运行,并为诸 ...
- 2022年2月国产数据库排行榜:冠军宝座面临挑战,OceanBase 重返 TOP3
大家好!文章开始本是用"新春快乐!虎年吉祥!"和大家打个招呼,无奈时间过得太快而文章整理得很慢,眼看崭新的三月还有几天就到来,那就在这里祝屏幕前的你在三月比二月更优秀! 月初,20 ...
- iOS中RunLoop和线程的关系
RunLoop又叫运行循环,主要用来管理线程.一个线程对应一个RunLoop,一个RunLoop又有五种模式.只有主线程的RunLoop是默认开启的,所以程序在开启后,会一直运行,不会退出.其他线程的 ...
- Blazor Hybrid 实战体验:那些你可能没预料到的坑没预料到的坑
前言 昨天写了一篇介绍 Blazor Hybrid 技术的文章,但限于篇幅,一些问题未能深入探讨.今天,我想继续记录使用 Blazor Hybrid 过程中遇到的几个问题,以及这个技术目前的一些局限性 ...
- 工作使用:Exchange问题汇总
工作使用:Exchange问题汇总 1:邮件不能发给公司内部的人,但是可以发公司外部人员 解析:GC出问题 2:xchange 2016环境,最近经常发生邮件队列堆积的现象.邮件服务器整体性能看上去没 ...