在线音频分析平台(后端设计)

源码展示于 github: 前端项目:
https://github.com/Zranshi/Audio-analysis-web-client
后端项目:
https://github.com/Zranshi/Audio-analysis-web-server

本章节我们主要探讨本项目的前端设计的部分.

本项目的后端主要做了两件事, 一是处理来自前端的 http 请求. 二是处理音频文件,将数据保存并返回响应.

http 请求以及响应

我们的上网流程大致来说是这样的:

  1. 我们打开浏览器,在地址栏输入我们想访问的网址,比如https://zranshi.github.io (当然你也可能从收藏夹里直接打开网站,但本质上都是一样的)
  2. 浏览器知道我们想要访问那个网址后,它在后台帮我们做了很多事情,主要就是把我们的访问意图包装成一个 http 请求,发给我们想要访问的网址所对应的服务器。通俗点说就是浏览器帮我们通知网站的服务器,说有人来访问你啦,访问的请求都写在 http 里了,你按照要求处理后告诉我,我再帮你回应他!
  3. 网站服务器处理了 http 请求,然后生成一段 http 响应给浏览器,浏览器解读这个响应,把相关的内容在浏览器里显示出来,于是我们就看到了网站的内容。比如你访问了 GitHub 主页https://github.com 服务器接收到这个请求后他就知道用户访问的是首页,首页显示的是全部仓库列表,于是它从数据库里把仓库数据取出来,生成一个写着这些数据的 html 文档,包装到 http 响应里发给浏览器,浏览器解读这个响应,把 html 文档显示出来,我们就看到了仓库列表的内容。

因此,django 作为一个 web 框架,它的使命就是处理流程中的第二步,接收浏览器发来的 http 请求,返回相应的 http 响应。于是引出这么几个问题:

1.Django 如何接收 http 请求?

Django 通过生成的文件目录下的 urls.py 文件来指定接收 http 请求. 可以在 urlpatterns 中配置接收请求的地址, Django 接收到请求后, 会从前往后依次匹配是否符合模式对应. 并在第一次匹配时返回响应.

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^get_wav/$', get_wav, name='get_wav'),
    url(r'^show_data/$', show_data, name='show_data'),
]

注意在匹配过程中, Django 使用正则表达式来进行匹配的. 并且当用户输入 127.0.0.1:8000 时, Django 会自动将域名和端口号去掉, 然后将剩下的字符串于列表中的元素匹配.

2.Django 如何处理这个 http 请求?

Django 每一个 view 函数的第一个参数都是 request . 因此我们在 view 的函数中处理 http 请求. 例如我们获取了一个音频文件上传的请求, 如果我们需要将它作为文件保存起来, 我可以在函数中将 request 请求的数据写入文件中.

@require_http_methods(['POST'])
def get_wav(request):
    response = {}
    myFile = None
    for i in request.FILES:
        myFile = request.FILES[i]
    if myFile:
        dir_path = os.path.join(os.path.join(BASE_DIR, 'static'), 'profiles')
        # 文件写入
        with open(os.path.join(dir_path, 'test.wav'), 'wb+') as destination:
            for chunk in myFile.chunks():
                destination.write(chunk)
        response['state'] = 'success'
    else:
        response['state'] = 'error'
    return JsonResponse(response)

3.Django 如何生成 http 响应?

在以上代码中, 我们可以看到最后返回了一个 JsonResponse 对象. 故而我们可以通过字典的形式将响应保存, 然后转换为 Json 返回给页面. 不仅仅是 Json 文件, Django 响应可以返回 HttpResponse 类及其子类, 具体可以返回:

  1. HttpResponse 类: 返回字符串
  2. JsonResponse 类: 返回 Json 类型文件
  3. StreamingResponse 类: 流式响应,返回大的文本文件
  4. FileResponse 类: 流式响应,返回大的二进制文件

解决跨域问题

什么是跨域请求

所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。

举个例子:假如一个域名为 aaa.cn 的网站,它发起一个资源路径为 aaa.cn/books/getBookInfo 的 axios 请求,那么这个请求是同域的,因为资源路径的协议、域名以及端口号与当前域一致(例子中协议名默认为 http,端口号默认为 80)。但是,如果发起一个资源路径为 bbb.com/pay/purchase 的 axios 请求,那么这个请求就是跨域请求,因为域不一致,与此同时由于安全问题,这种请求会受到同源策略限制。

由于使用了前后端分离的架构, 前端项目和后端项目不在同一个端口中. 故而会存在跨域问题, 需要设置来进行解决.

解决方法

为了解决跨域问题, 我使用 django-cors-headers 插件来进行解决. 需要在 setting.py 中添加配置, 并将需要提交请求的地址添加进入白名单(白名单也可以使用正则表达式匹配)

# 注册应用
INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]
# 注册中间件
MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    ...
]
#设置白名单
CORS_ORIGIN_WHITELIST = (
    'http://localhost:8080',
    'http://127.0.0.1:8080',
)

正是你花费在玫瑰上的时间才使得你的玫瑰花珍贵无比