整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

一个比较无语的事情,一个接口要求返回json形式

一个比较无语的事情,一个接口要求返回json形式

个比较无语的事情,一个接口要求返回Application/json形式,在接受响应时提示content type [text/html;charset=utf-8],前面还有一大串,简而言之就是格式不对转化失败,而写接口的人也说是返回的json形式。

我用postman去测试,发现能调通,看上去确实是json格式,但是我换了很多种形式去接收请求响应,都是提示格式转化失败。遇到这种问题甩锅都不知道怎么甩,反正就是人和代码一个能跑就行。

在我不知道怎么办的时候,打开了请求头,发现类型居然是text/json,这下直接贴脸开大,截图甩到脸上,不出意外,这个接口又是用json写的,这也算是一个坑。

小节基本要求

  • 了解html文件

要点:

  1. JSON格式的数据
  2. Javascript(简称js)语言
  3. 样式选择器之ID选择器

目前样式:


目标:

利用Ajax动态获取文章数据,成就动态页面。


Step1:构建JSON格式数据

新建文件夹,建立一个.json后缀的文件,这个文件里存放的是我们的文章数据。


代码如下:

{
  "hot": [
    {  "id": 1,
      "title": "Zabbix"
    },
    {
      "id": 2,
      "title": "Prometheus"
    },
    {
      "id": 3,
      "title": "Java yyds!"
    },
    {
      "id": 4,
      "title": "什么?卡卡罗特对波又输了?"
    },
    {
      "id": 5,
      "title": "一千零一夜"
    },
    {
      "id": 100,
      "title": "问风"
    }
  ],
  "new": [
    {  "id": 6,
      "title": "ElasticSearch"
    },
    {
      "id": 7,
      "title": "Kafka"
    },
    {
      "id": 8,
      "title": "从你的全世界路过"
    },
    {
      "id": 9,
      "title": "如果那天可以好好聊聊"
    },
    {
      "id": 10,
      "title": "带着记忆回到14年"
    },
    {
      "id": 11,
      "title": "孤流拒海"
    }
  ]
}
  • hot:最热文章列表
  • new:最新文章列表
  • 共计12篇文章标题

什么?你问我JSON格式的数据为什么长这样?为什么带个{},为什么带个[ ]?

因为大家都这样写,所有就成这样咯。

ps:现在开发网站几乎全部都是用的json格式构建的数据。学会这种格式,难道不重要吗?

这是一个很火的学习网站:www.baidu.com

Step2:Id选择器使用


这点作了修改,给ul添加了Id选择器。

为什么添加ID选择器,看Step4

Step3:引入jquery文件:这是个工具

下载地址:https://code.jquery.com/jquery-1.11.0.min.js

直接右键屏幕另存为就可以了。

创建js文件夹,将文件放入,并且在body.html页面引入该文件:如下:


<script  src="../js/jquery-3.1.1.js"></script>


Step4: Ajax请求json文件,获取json数据

代码如下:

<script type="text/javascript">

    function getData() {
        $.ajax({
            type: "GET",
            url: "../data/article.json",
            dataType: "json",
            headers:{'Content-Type':'application/json;charset=utf8'},
            success: function (res) {

                let hot_w=res.hot;
                let new_w=res.new;

                var hot_html=""
                var new_html=""

                hot_w.forEach(function (d) {

                    var h="<li>" + d.title + "</li>"

                    hot_html +=h;

                })

                new_w.forEach(function (d) {

                    var n="<li>" + d.title + "</li>"

                    new_html +=n;
                })

                console.log($.parseHTML(hot_html))

                console.log($(".hot .card-body ul"))
                $("#hot-w").append($.parseHTML(hot_html))
                $("#new-w").append($.parseHTML(new_html))
            }
        })
    }

    getData()

</script>

Step5:右键运行,结果如下:




附本篇body.html中的所有追加的代码:

JS部分:

<script  src="../js/jquery-3.1.1.js"></script>
<script type="text/javascript">

    function getData() {
        $.ajax({
            type: "GET",
            url: "../data/article.json",
            dataType: "json",
            headers:{'Content-Type':'application/json;charset=utf8'},
            success: function (res) {

                let hot_w=res.hot;
                let new_w=res.new;

                var hot_html=""
                var new_html=""

                hot_w.forEach(function (d) {

                    var h="<li>" + d.title + "</li>"

                    hot_html +=h;

                })

                new_w.forEach(function (d) {

                    var n="<li>" + d.title + "</li>"

                    new_html +=n;
                })

                console.log($.parseHTML(hot_html))

                console.log($(".hot .card-body ul"))
                $("#hot-w").append($.parseHTML(hot_html))
                $("#new-w").append($.parseHTML(new_html))
            }
        })
    }

    getData()

</script>

body部分:

<body>

<div class="tbody">
    <main class="is-main">
        <div class="main-left">
            <div class="gonggao">
                哈喽,我是公告位
            </div>
            <div class="panel">
                <div class="guangao">哈喽,我是广告位</div>
            </div>
            <div class="content">
                <div class="card">
                    <div class="hot">
                        我是热门文章
                    </div>
                    <div class="card-body">
                            <ul id="hot-w">

                            </ul>
                    </div>
                </div>
                <div class="card">
                    <div class="new">
                        我是最新文章
                    </div>
                    <div class="card-body">
                        <ul id="new-w">

                        </ul>
                    </div>
                </div>
            </div>
        </div>
        <div class="main-right">
<!--            <div class="my-info">-->
<!--                    我是个人信息框-->
<!--            </div>-->
        </div>
    </main>
</div>


</body>

我都用了哪些新知识:

  • ajax:

一种用于请求网址的技术

  • Javascript(简称JS):

一种脚本语言,你所看到的所有网站都离不开这门技术

  • css选择器之id选择器:

样式选择器,前几篇讲过类选择器,详细了解入口,www.baidu.com

  • json格式的数据:

你所看到的所有网站的数据目前几乎都是以JSON格式交互的



在前面

今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受。这么好的光阴怎么浪费,睡觉、吃饭、打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完。

这篇文章比较基础,在国庆期间的业余时间写的,这几天又完善了下,力求把更多的前端所涉及到的关于文件上传的各种场景和应用都涵盖了,若有疏漏和问题还请留言斧正和补充。

自测读不读

以下是本文所涉及到的知识点,break or continue ?

  • 文件上传原理
  • 最原始的文件上传
  • 使用 koa2 作为服务端写一个文件上传接口
  • 单文件上传和上传进度
  • 多文件上传和上传进度
  • 拖拽上传
  • 剪贴板上传
  • 大文件上传之分片上传
  • 大文件上传之断点续传
  • node 端文件上传

原理概述

原理很简单,就是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。

我们都知道如果要上传一个文件,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法。

那么multipart/form-data表示什么呢?

multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。

multipart/form-data 结构

看下 http 请求的消息体



  • 请求头:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———XXX开始,以———XXX结尾。

  • 消息体- Form Data 部分

每一个表单项又由Content-Type和Content-Disposition组成。

Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。

Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。

解析

客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。

可能大家马上能想到通过正则或者字符串处理分割出内容,不过这样是行不通的,二进制buffer转化为string,对字符串进行截取后,其索引和字符串是不一致的,所以结果就不会正确,除非上传的就是字符串。

不过一般情况下不需要自行解析,目前已经有很成熟的三方库可以使用。

至于如何解析,这个也会占用很大篇幅,后面的文章在详细说。

最原始的文件上传

使用 form 表单上传文件

在 ie时代,如果实现一个无刷新的文件上传那可是费老劲了,大部分都是用 iframe 来实现局部刷新或者使用 flash 插件来搞定,在那个时代 ie 就是最好用的浏览器(别无选择)。

DEMO



这种方式上传文件,不需要 js ,而且没有兼容问题,所有浏览器都支持,就是体验很差,导致页面刷新,页面其他数据丢失。

HTML

 <form method="post" action="http://localhost:8100" enctype="multipart/form-data">

        选择文件:
            <input type="file" name="f1"/> input 必须设置 name 属性,否则数据无法发送<br/>
<br/>
            标题:<input type="text" name="title"/><br/><br/><br/>

        <button type="submit" id="btn-0">上 传</button>

</form>

复制代码

文件上传接口

服务端文件的保存基于现有的库koa-body结合 koa2实现服务端文件的保存和数据的返回。

在项目开发中,文件上传本身和业务无关,代码基本上都可通用。

在这里我们使用koa-body库来实现解析和文件的保存。

koa-body 会自动保存文件到系统临时目录下,也可以指定保存的文件路径。



然后在后续中间件内得到已保存的文件的信息,再做二次处理。

  • ctx.request.files.f1 得到文件信息,f1为input file 标签的 name
  • 获得文件的扩展名,重命名文件

NODE

/**
 * 服务入口
 */
var http=require('http');
var koaStatic=require('koa-static');
var path=require('path');
var koaBody=require('koa-body');//文件保存库
var fs=require('fs');
var Koa=require('koa2');

var app=new Koa();
var port=process.env.PORT || '8100';

var uploadHost=`http://localhost:${port}/uploads/`;

app.use(koaBody({
    formidable: {
        //设置文件的默认保存目录,不设置则保存在系统临时目录下  os
        uploadDir: path.resolve(__dirname, '../static/uploads')
    },
    multipart: true // 开启文件上传,默认是关闭
}));

//开启静态文件访问
app.use(koaStatic(
    path.resolve(__dirname, '../static') 
));

//文件二次处理,修改名称
app.use((ctx)=> {
    var file=ctx.request.files.f1;//得道文件对象
    var path=file.path;
    var fname=file.name;//原文件名称
    var nextPath=path+fname;
    if(file.size>0 && path){
        //得到扩展名
        var extArr=fname.split('.');
        var ext=extArr[extArr.length-1];
        var nextPath=path+'.'+ext;
        //重命名文件
        fs.renameSync(path, nextPath);
    }
    //以 json 形式输出上传文件地址
    ctx.body=`{
        "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
    }`;
});

/**
 * http server
 */
var server=http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ......   ');
复制代码

CODE

https://github.com/Bigerfe/fe-learn-code/