.net 与java对接时间处理_.net api 和java平台对接技术总结

这两天 一直和京东对接接口,我们用.net api 提供接口,对方用java调用,本来没什么问题,但是对方对数据安全要求特别严,要验签,于是噩梦开始了。

1、在传输的时候,约定传输格式:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);//+ "?RequestData="+ param

request.Method = "POST";

request.ContentType= "application/json";//参数是接送//request.ContentType = "application/x-www-form-urlencoded";//参数为&拼接

request.ContentLength = param.Length;

2、双方平台对编码不一致,所以在对数据进行MD5加密前,先进行UTF8编码:

byte[] md5Token =md5.ComputeHash(Encoding.UTF8.GetBytes(data));string base64Token = Convert.ToBase64String(md5Token);

3、我们遇到了这个问题:https://bbs.csdn.net/topics/340058520

具体的描述就是C#和java对二进制的编码值不一样

java byte : -128~127

C#   byte : 0~255

但是,这只是视觉欺骗,做硬件的经理说,虽然两边看到对字符的编码得到的值不一样,但是,实际上,计算机对这个的值的识别是一样的。所以这根本就不是个问题。但是对方特别有毅力,反复的试了各种编码格式,于是我就跟在他后面,一个一个的试,又是远程合作,不得不佩服,研究生果然比我这种本科毕业的做事有毅力,然而,最后发现,是他在做加密的时候,忘记把私钥放进去了。哎,感觉身体被掏空┭┮﹏┭┮

4、Cookie在传输的过程中,+、/、=会丢失,所以使用了替换

string base64Token2 = base64Token.Replace('+', '-').Replace('/', '_').Replace('=', '*');

5、我们使用模型接收数据,这时候,会出现数据接收不到的情况,那么上面1的ContentType 就显得比较重要了,既然我上面已经注释了,就不多写了。

6、应为我们使用模型接收数据,而对方见有的数据不是必填的,所以就没有写,这样对方填3个参数,进行加密计算,而我这边会把没有填的null值也加进来进行加密计算,并且计算的时候,我们这边采用序列化,使用两边还要对参数进行排序,所以,我们的加密结果始终不一样,崩溃┭┮﹏┭┮,中间考虑过用string接收参数,但是api不支持直接接收string参数,必须要加一个[FromBody]的标记,然而,问题有开始来了,对方的请求,根本进不来,继续崩溃┭┮﹏┭┮。最终我们还是使用模型对数据进行接收,不过接收参数的方式改了一下,用流来接收,这样,对方传什么,我们接收的就是什么,具体代码如下:

这是原来的代码

var jsonSetting = new JsonSerializerSettings { NullValueHandling =NullValueHandling.Ignore };var dataOld = JsonConvert.SerializeObject(actionContext.ActionArguments[ArgumentsName], Formatting.Indented, jsonSetting);//这两行用来去除为空的参数

dataOld= JsonSort.SortJson(JToken.Parse(dataOld), null);//排序

这是修改后的代码

Stream stream =HttpContext.Current.Request.InputStream;

StreamReader streamReader= newStreamReader(stream);

responseJson= streamReader.ReadToEnd();

可以看到 接收参数的方式由 actionContext.ActionArguments[ArgumentsName] 换成了下面的 streamReader.ReadToEnd();如果有哪位大神指导string类型的怎么发送,怎么接收,还请告知一下,毕竟第一次做,没有经验

7、整体的验签处理使用的是ActionFilterAttribute 拦截,具体的思路就是,将秘钥各自保存一份,将数据用秘钥加密,然后将验签的Token可用户标识(不是秘钥)写一份到cookie里面,然后逻辑上就可以不做任何更改直接使用啦

具体的代码如下,但是验签部分因为对方是京东,还是省略的好,大家可以根据自己的应用场景脑补

usingAito.Entity;usingAito.ServBll.JDBll;usingNewtonsoft.Json;usingNewtonsoft.Json.Linq;usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Net;usingSystem.Net.Http;usingSystem.Net.Http.Headers;usingSystem.Security.Cryptography;usingSystem.Text;usingSystem.Threading;usingSystem.Threading.Tasks;usingSystem.Web;usingSystem.Web.Http;usingSystem.Web.Http.Controllers;usingSystem.Web.Http.Filters;usingSystem.Web.Script.Serialization;usingZP.Comm;namespaceAito.JDService

{///

///在action执行前后做额外处理///

public classTokenProjectorAttribute : ActionFilterAttribute

{public string TokenName { get; set; } = "Token";public string UserTagName { get; set; } = "UserTag";public string ArgumentsName { get; set; } = "RequestData";public string UserInfoName { get; set; } = "UserInfo";///

///在action执行之前验证Token的合法性///

///

//public override void OnActionExecuting(HttpActionContext actionContext)

public overrideTask OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)

{string token = "",tag="";

CookieHeaderValue cookieToken= actionContext.Request.Headers.GetCookies(TokenName).FirstOrDefault();//从cookie中取出Token

if (cookieToken == null)

ThrowException(new JDServiceModel() { Success = false, Code = -4001, Msg = "Token不能为空!", Data = ""});

CookieHeaderValue cookieTag= actionContext.Request.Headers.GetCookies(UserTagName).FirstOrDefault();//从cookie中取出用户标识

if (cookieTag == null)

ThrowException(new JDServiceModel() { Success = false, Code = -4002, Msg = "用户标识能为空!", Data = ""});

token= cookieToken[TokenName].Value;//获取到Token

tag = cookieToken[UserTagName].Value;//获取到Tag

int userID = -1;if(!int.TryParse(tag,outuserID))

ThrowException(new JDServiceModel() { Success = false, Code = -4007, Msg = "用户标识错误!", Data = ""});//验证用户合法性

if (CommOpreJD.UserInfos.Where(u => u.UserID == userID).Count() < 1)

ThrowException(new JDServiceModel() { Success = false, Code = -4003, Msg = "用户标识不合法!", Data = ""});//验证数据的合法性

if (!actionContext.ActionArguments.ContainsKey(ArgumentsName))

ThrowException(new JDServiceModel() { Success = false, Code = -4004, Msg = "请求参数不能为空!", Data = ""});string msg = "68行:请求Token:"+ token + "\n";

msg+= "UserTag:" + tag + "\n";

ErrHandler.WriteServerInfo(msg);//====================================================参数验证

var modelState =actionContext.ModelState;if (!modelState.IsValid)

{string error = string.Empty;foreach (var key inmodelState.Keys)

{var state =modelState[key];if(state.Errors.Any())

{

error=state.Errors.First().ErrorMessage;if(String.IsNullOrEmpty(error))

{

error= "请求参数缺失或错误";

}break;

}

}

ThrowException(new JDServiceModel() { Success = false, Code = -4008, Msg = "参数验证失败-" + error, Data = ""});

}//====================================================参数验证//校验数据是否被篡改

UserInfoServModel model = CommOpreJD.UserInfos.Where(u => u.UserID == userID).ToList()[0];#region 验签

string responseJson = string.Empty;try{

Stream stream=HttpContext.Current.Request.InputStream;

StreamReader streamReader= newStreamReader(stream);

responseJson=streamReader.ReadToEnd();//responseJson = JsonSort.SortJson(JToken.Parse(responseJson), null);

}catch{ }//var jsonSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };//var dataOld = JsonConvert.SerializeObject(actionContext.ActionArguments[ArgumentsName], Formatting.Indented, jsonSetting);//这两行用来去除为空的参数//dataOld = JsonSort.SortJson(JToken.Parse(dataOld), null);此处为验签操作,目的是计算出 base64Token2

msg= "108行:用户数据:" + data + "\n";

msg+= "用户Token:" + token + "\n";

msg+= "校验Token:" + base64Token2 + "\n";

ErrHandler.WriteServerInfo(msg);if (base64Token2 !=token)

ThrowException(new JDServiceModel() { Success = false, Code = -4005, Msg = "数据被篡改!", Data = ""});#endregion

actionContext.Request.Properties[UserInfoName]=model;return base.OnActionExecutingAsync(actionContext, cancellationToken);

}private void ThrowException(JDServiceModelexp)

{var response = newHttpResponseMessage();

response.Content= new StringContent(newJavaScriptSerializer().Serialize(exp));

response.StatusCode=HttpStatusCode.Conflict;throw newHttpResponseException(response);

}///

///在Action方法调用后,result方法调用前执行,使用场景:异常处理。///

///

//public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)

public overrideTask OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)

{string resultData =GetResponseValues(actionExecutedContext);object user = null;if (!actionExecutedContext.Request.Properties.TryGetValue(UserInfoName, outuser))

ThrowException(new JDServiceModel() { Success = false, Code = -4006, Msg = "数据返回时,用户信息丢失!", Data = ""});//HttpStatusCode StatusCode = actionExecutedContext.ActionContext.Response.StatusCode;//取得由 API 返回的状态代码

JDServiceModel result = actionExecutedContext.ActionContext.Response.Content.ReadAsAsync>().Result;//取得由 API 返回的资料

result.Success = actionExecutedContext.ActionContext.Response.IsSuccessStatusCode; //请求是否成功此处为验签操作,目的是计算出 base64Token2

result.Token =base64Token2;//重新封装回传格式

actionExecutedContext.Response =ToJson(result);string msg = "返回数据:" + result.Data + "\n";

msg+= "返回Token:" + base64Token2 + "\n";

ErrHandler.WriteServerInfo(msg);

ErrHandler.WriteServerInfo(msg);return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);//base.OnActionExecuted(actionExecutedContext);

}///

///读取action返回的result///

///

///

private stringGetResponseValues(HttpActionExecutedContext actionExecutedContext)

{

Stream stream=actionExecutedContext.Response.Content.ReadAsStreamAsync().Result;

Encoding encoding=Encoding.UTF8;/*这个StreamReader不能关闭,也不能dispose, 关了就傻逼了

因为你关掉后,后面的管道 或拦截器就没办法读取了*/

var reader = newStreamReader(stream, encoding);string result =reader.ReadToEnd();/*这里也要注意: stream.Position = 0;

当你读取完之后必须把stream的位置设为开始

因为request和response读取完以后Position到最后一个位置,交给下一个方法处理的时候就会读不到内容了。*/stream.Position= 0;returnresult;

}privateHttpResponseMessage ToJson(Object obj)

{

String str;if (obj is String || obj is Char)//如果是字符串或字符直接返回

{

str=obj.ToString();

}else//否则序列为json字串

{

JavaScriptSerializer serializer= newJavaScriptSerializer();

str=serializer.Serialize(obj);

}

HttpResponseMessage result= new HttpResponseMessage { Content = new StringContent(str, Encoding.GetEncoding("UTF-8"), "application/json") };returnresult;

}

}

}

参考出处:

https://www.cnblogs.com/hnsongbiao/p/7039666.html

https://www.cnblogs.com/goodlucklzq/p/4481956.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值