目录导航:
前言:
什么是multipart/form-data请求:
Html上传图片按钮:
使用ajax将图片文件流和相关参数传递到后端进行拼接:
后端接收图片和参数,并将图片文件流转化为图片字节类型数据:
重点,HttpClient拼接multipart/form-data形式参数post提交数据:
使用Fiddler 4 抓包查看请求的参数:
总结:
文章正文:
回到顶部
前言:
本次要讲的是使用.Net HttpClient拼接multipark/form-data形式post上传文件和相关参数,并接收到上传文件成功后返回过来的结果(图片地址,和是否成功)。可能有不少人会说用ajax不是就能够轻松的实现吗?的确是在不存在跨域问题的前提下使用ajax上传文件,接收返回结果是最佳的选择。无奈的是咱们对接的是第三方的一个上传图片的接口,并且对方并无对咱们的域名设置容许跨域,为了可以解决这一问题咱们只可以经过后端请求避免跨域问题。
回到顶部
什么是multipart/form-data请求:
关于multipart/form-data详情查看: https://www.cnblogs.com/tylerdonet/p/5722858.html
回到顶部
Html上传图片按钮:
<div class="cover-hd">
<a href="javascript:;" class="a-uploadCustom">
<input type="file" id="Logoimg" onchange="OnchangeImage(this)" /></a>
</div>
回到顶部
使用ajax将图片文件流和相关参数传递到后端进行拼接:
注意:由于我这里调用第三方接口须要传递(appid应用程序惟一标识,random随机数,和sign签名)
复制代码
<script type="text/javascript">
//后端图片上传
function OnchangeImage(obj) {
var formData = new FormData();
var files = $(obj).prop('files'); //获取到文件列表
console.log(files[0]);
formData.append("imgType", 1);
formData.append("appId","你须要传递的参数");
formData.append("random", "你须要传递的参数");
formData.append("file", files[0]);//图片文件流
formData.append("sign", "你须要传递的参数");
console.log(formData);
jQuery.support.cors = true;
$.ajax({
async: true,
contentType: false, //头部请求内容格式
dataType: 'json',
type: 'post',
data:formData,
// 告诉jQuery不要去处理发送的数据
processData: false,
url: "@Url.Action("ImageUpload", "MtVirtualStore")",//后端接收图片接口
success: function(data) {
//后端Httpclient请求成功后返回过来的结果
console.log(data);
}
});
}
</script>
复制代码
如今几乎大部分的App都支持使用多个第三方帐号进行登陆,如:微信、QQ、微博等,咱们把此称为多帐号统一登录。而这些帐号的表设计,流程设计相当重要,否则后续扩展性贼差。本文不提供任何代码实操,可是梳理一下博主根据我司帐号模块的设计,提供思路,仅供参考。
1、 自建的登录体系
1.1 手机号登录注册
该设计的思路是每一个手机号对应一个用户,手机号为必填项。
流程:
首先输入手机号,而后发送到服务端。先判断该手机号是否存在帐号,若是没有,就会生成随机验证码,将手机号和验证码绑定到Redis中,并设置必定的过时时间(过时时间通常是5分钟,这就是咱们通常手机验证码的有效期),最后将验证码经过短信发送给用户。
用户接收到验证码后,在界面填写验证码以及密码等基础信息,而后将这些数据发送服务端。服务端收到后,先判断在Redis里面这个手机号对应的验证码是否一致,,失败就返回错误码,成功就给用户建立一个帐号和保存密码。
注册成功后,用户便可经过本身的手机号+密码进行登录。
问题:
用户体验差,须要完成获取验证码,填写验证码/密码/用户名等诸多的信息完成注册,而后才能使用;
容易遗忘密码,遗忘后,只能经过忘记密码来从新设置密码。
1.2 优化注册登录
该方案的思路是弱化密码的必填性,即不管用户是否注册过,可经过手机号 + 验证码 直接进行登录(保留手机号 + 密码登陆的方式)。
流程:
输入手机号,而后发送到服务端。服务端生成随机验证码,将手机号和验证码绑定到Redis中,并设置必定的过时时间(过时时间通常是5分钟,这就是咱们通常手机验证码的有效期),最后将验证码经过短信发送给用户。
用户接收到验证码后,在界面只需填写收到的验证码,提交到服务端。服务端收到后,先判断在Redis里面这个手机号对应的验证码是否一致,失败就返回错误码,成功就直接登陆。若是是老用户,直接拉取用户信息;若是是新用户,则提示他能够完善用户信息(不强制)。
用户经过手机号 + 验证码登陆后,也可选择设置密码,而后就能够经过手机号 + 密码的方式登陆,即:密码是非必填项。
用户表设计:
id user_name user_password user_mobile state more
用户id 用户名 用户密码 手机号码 帐号状态 其余信息
1.3 引入第三方帐户方案
1.3.1 微博登陆
进入 Web2.0 时代 ,微博开放了第三方网站登陆, 产品说, 这个咱们得要, 加个用微博账号就能登陆咱们的App吧,并且得和咱们本身的用户表关联。
流程:
客户端调用微博登陆的界面,进行输入用户名、密码,登陆成功后,会返回access_token,经过access_token调取API接口获取用户信息。
服务端经过用户信息在咱们用户表建立一个帐号,之后,该第三方帐号便可经过该微博帐号直接进行登录。
微博用户信息表设计:
id user_id uid access_token
主键id 用户id 微博惟一id 受权码
1.3.2 噩梦来临
紧接着, QQ又开放用户登陆了, 微信开放用户登陆了,网易开发用户登陆了。。。。。。一会儿要接入好多家第三方登陆了, 只能按照 “微博用户信息表” 新建一个表,重写一套各个第三方登陆。
2、 优化帐号体系
2.1 原帐号体系分析
自建登录体系:不管 手机号 + 密码 , 仍是 手机号 + 验证码 , 都是一种 用户信息+密码 的验证形式;
第三方登陆:也是用户信息+密码 的形式, 用户信息即第三方系统中的 ID(第三方系统中的惟一标识), 密码即 access_token, 只不过是一种有使用时效按期修改的密码。
回到顶部
后端接收图片和参数,并将图片文件流转化为图片字节类型数据:
复制代码
//接收前端图片文件信息
[HttpPost]
public JsonResult ImageUpload(FormContext context)
{
HttpPostedFileBase fileData = Request.Files[0];
string appId=Request["appId"];
string random=Request["random"];
string sign=Request["sign"];
string imgType=Request[www.jintianxuesha.com"imgType"];
if (fileData != null)
{
try{
string fileName = Path.GetFileName(fileData.FileName);//原始文件名称
byte[] byteFileData = ReadFileBytes(fileData);//文件流转为字节流
var resultContext =HttpClientPostUpload(byteFileData,appId,random,sign,imgType, fileName);
return Json(new { code = 1, list = resultContext,msg="上传成功~"});
}
catch (Exception ex)
{
return Json(new { code = 0, msg = ex.Message });
}
}
else
{
return Json(new { code = 0, msg = "图片上传失败,请稍后再试~" });
}
}
//文件流转化为字节
/// <summary>
/// 文件流类型转化字节类型
/// </summary>
/// <param name="fileData"www.seocelve.com>文件流数据</param>
/// <returns></returns>
private byte[] ReadFileBytes(www.haishenyul.com HttpPostedFileBase fileData)
{
byte[] data;
using (Stream inputStream = fileData.InputStream)
复制代码
回到顶部
重点,HttpClient拼接multipart/form-data形式参数post提交数据:
复制代码
/// <summary>
/// 向目标地址提交图片文件参数数据
/// </summary>
/// <param name="bmpBytes">图片字节流</param>
/// <param name="appId">appid</param>
/// <param name="random">随机数</param>
/// <param name="sign">签名</param>
/// <param name="imgType">上传图片类型</param>
/// <param name="fileName">图片名称</param>
/// <returns></returns>
public string HttpClientPostUpload(byte [www.pingguoyul.cn bmpBytes, string appId, string random,,string sign,string imgType,string fileName)
{
using (var client = new HttpClient())
{
List<ByteArrayContent>www.yuanhuapt.cn list = new List<ByteArrayContent>();
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(appId));
dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")//内容处置标头
{
Name = "appId"
};
list.Add(dataContent);
var dataContent2 = new ByteArrayContent(Encoding.UTF8.GetBytes(imgType));
dataContent2.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "imgType"
};
list.Add(dataContent2)www.yasenyuLee.cn;
var dataContent3 www.jiuhaoyulept.com= new ByteArrayContent(Encoding.UTF8.GetBytes(random));
dataContent3.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "random"
};
list.Add(dataContent3);
var dataContent4 = new ByteArrayContent(Encoding.UTF8.GetBytes(sign));
dataContent4.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "sign"
};
list.Add(dataContent4);
List<ByteArrayContent>www.yasenyuLe.com list2 = new List<ByteArrayContent>();
var fileContent = new ByteArrayContent(bmpBytes);//填充图片字节
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name="file",
FileName=fileName
list.Add(fileContent)
using (var content =new MultipartFormDataContent())
Action<List<ByteArrayContent>> act =www.tongyayuLe.cn (dataContents) =>
{//声明一个委托,该委托的做用就是将ByteArrayContent集合加入到MultipartFormDataContent中
foreach (var byteArrayContent in dataContents)
act(list);//执行act
try
复制代码
回到顶部
使用Fiddler 4 抓包查看请求的参数:
由于咱们没有办法看到咱们所拼接成功后的multipark/form-data形式的数据,想要看到对应拼接的请求参数可使用 Fiddler 4 抓包工具查看:
关于Fiddler 4抓包工具的使用能够阅读该篇博客:https://www.zongxyuLe.com /p/55f7be58a7e4
抓包获取到的multipark/form-data形式的请求参数以下图:
回到顶部
总结:
写到最后才发现,本来只须要一个简单的请求就能够解决的问题由于跨域把这个问题变得如此繁琐,搞得真叫人蛋痛。这里我试过了不少种方式拼接multipark/form-data形式的请求参数,最后在坚持不懈的尝试下终于成功了。javascript