• jquery使用ajax


    0202年了, jQuery可以继续梭哈...
    记录一下jQuery使用ajax上传文件Post表单的操作

    相关文档: jQuery官方ajax文档

    上传文件

    仅上传单个文件

    前端jquery使用FormData构造请求数据

    <!-- 防止点击提交按钮页面自动刷新, 所以设置 onsubmit="return false;" -->
    <form onsubmit="return false;" method="post" class="form-group">
        <div>
            <input type="file" id="i-avatar" name="image" />
        </div>
        <div class="mt-2">
            <button class="btn btn-primary" onclick="uploadImage()">提交</button>
        </div>
    </form>
    
    <script type="text/javascript">
        function uploadImage() {
            const form = new FormData();
            form.append("file", $("#i-avatar").prop("files")[0]);
            $.ajax({
                type: "post",
                url: "/videos/image",
                contentType: false,
                data: form,
                processData: false,
                success: function () {
                    window.alert("success");
                }
            });
        }
    </script>
    

    后端Action:

    [HttpPost("image")]
    public async Task<IActionResult> UploadImage([FromForm] IFormFile file)
    {
        using (var rs = file.OpenReadStream())
        {
            string path = Path.Combine(_webHostEnvironment.WebRootPath, "upload", "images", file.FileName);
            Directory.CreateDirectory(Path.GetDirectoryName(path));
            using (var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                await rs.CopyToAsync(fs);
                await fs.FlushAsync();
            }
        }
    
        return Ok();
    }
    

    这里就是拿到文件流然后保存到~/wwwroot/upload/image文件夹下, 这里文件名直接使用了用户上传的文件名, 微软官方文档中不建议这么做, 因为可能会有安全问题

    写好之后在浏览器中测试, 看一下最终发出的请求是什么样的

    alt

    可以看到, 虽然我们再ajax函数中将contentType设置成了false, 但是浏览器自动为我们添上了 content-type: multipart/form-data; boundary=----WebKitFormBoundaryxZyRmmXUfCxJRX7A, 一开始我手动设置了contentType: multipart/form-data, 这样肯定是不行的, 至于为什么, 因为没有设置boundary这个东西啊

    简单总结一下ajax要注意的配置

    dataType, 表示期望服务器返回的类型, 这个不能乱填, 如果返回的格式是json则设置为 json, 返回的是纯文字, 则设置为 text, 这个属性还可以被设置为 xml, html, script, jsonp, 如果不设置这个属性, 那么jQuery会根据响应的MIME来自动推断, 如果你不确定响应的格式, 那么就不要设置这个属性;

    contentType, 发送数据给服务器时, 指定的数据的格式, 注意, 一定要注意, 这个属性是有默认值的, 且默认值是 application/x-www-form-urlencoded; ciharset=UTF-8, 如果服务器不接受这种类型的输入, 那么就会请求失败, 所以务必确认好再设置, 如果将这个属性设置为false, 那么jquery就不会在请求头的加入content-type

    processData, 告诉jquery, 是否要将请求数据内容转换成 application/x-www-form-urlencoded, 默认是true, 也就是说jquery会将ajax的data属性格式化成 application/x-www-form-urlencoded 这种数据格式, 关于Post请求的数据格式的问题, 可以看这篇博文, HTTP_POST请求的数据格式, 非常详细, 如果是上传文件的场景, 要将这个属性设置成 false

    上传文件的同时, 再传一些其他 Key-Value 类型数据

    在用户注册的场景下, 需要提交用户名, 密码和头像等信息, 头像往往是一个图片文件; 当然, 也可以先单独上传头像, 然后传图片的url给用户注册接口api, 但是, 我觉得更好的做法是直接把文件一起传给用户注册接口的api, 这个接口同时保存用户头像;

    还是使用FormData对象来构造请求数据:

    <form onsubmit="return false;">
        <div>
            <label>
                用户名:&nbsp;<input type="text" id="username" name="username" value="" />
            </label>
        </div>
        <div>
            <label>
                密码:&nbsp;<input type="password" id="password" name="password" value="" />
            </label>
        </div>
        <div>
            <label>
                头像:&nbsp;<input type="file" id="avatar" name="avatar" value="" multiple/>
            </label>
        </div>
        <div><button class="btn btn-primary" onclick="registerUser()">注册</button></div>
        <div id="register-result"></div>
    </form>
    
    <script type="text/javascript">
        function registerUser() {
            const formData = new FormData();
            formData.set("username", $("#username").val());
            formData.set("password", $("#password").val());
            const files = $("#avatar").prop("files");
            if (files && files.length > 0)
                formData.set("avatar", files[0]);
            // 如果有多个文件怎么办?
            //for (let i = 0; i < files.length; i++) {
            //    formData.set(i, files[i]);
            //}
            $.ajax({
                url: "/user",
                type: "post",
                processData: false,
                contentType: false,
                data: formData,
                success: function (result) {
                    $("#register-result").text(JSON.stringify(result));
                }
            });
        }
    </script>
    

    后台接收数据:

    [HttpPost]
    public Task<IActionResult> Register([FromForm] IFormCollection form)
    {
        return Task.FromResult<IActionResult>(Ok(form));
    }
    

    测试看一下请求是什么样的

    alt

    可以看到 content-type 依旧是 multipart/formdata; boundary...这种, 但是, 如果我要在传图片的同时, 传一些其他数据数据或者复杂对象怎么办啊? 比如我后台定义这样的对象:

    public class VideoTagDto
    {
        public string TagName { get; set; }
        public DateTime CreateDate { get; set; }
    }
    
    public class ActorDto
    {
        public string Name { get; set; }
        public string Sex { get; set; }
        public string Country { get; set; }
        public DateTime Birth { get; set; }
    }
    
    public class VideoDto
    {
        public string Name { get; set; }
        public DateTime PublishDate { get; set; }
        public IList<VideoTagDto> VideoTags { get; set; }
        public IList<ActorDto> Actors { get; set; }
        public IFormFile CoverImage { get; set; }
    
        public VideoDto()
        {
            VideoTags = new List<VideoTagDto>();
            Actors = new List<ActorDto>();
        }
    }
    

    前台有没有办法可以让后台接口接收到 VideoDto 呢? VideoDto 里面包含了 IFormFile 类型 CoverImage;

    不好意思, 好像不太可以, 我尝试了希望使用 application/json 格式来上传文件和其他复杂对象, 不过浏览器的File对象没办法序列化成JSON格式; 所以只能先上传文件, 然后拿到文件的url, 再和其他数据一起上传

  • 相关阅读:
    模板驱动表单中的自定义表单验证
    kartikgridGridView导出excel变科学计数
    linux下安装vue-element-admin报错
    yii2运行流程
    nginx报错502 Bad Gateway
    linux下安装npm
    登录验证记录
    vue的store、vuex状态管理
    vue-cli3使用路由和循环引入路由
    vue使用问题汇总记录
  • 原文地址:https://www.cnblogs.com/Laggage/p/13414733.html
Copyright © 2020-2023  润新知