在线音频分析平台(后端设计)
源码展示于 github: 前端项目:
https://github.com/Zranshi/Audio-analysis-web-client
后端项目:
https://github.com/Zranshi/Audio-analysis-web-server
本章节我们主要探讨本项目的前端设计的部分.
本项目的后端主要做了两件事, 一是处理来自前端的 http 请求. 二是处理音频文件,将数据保存并返回响应.
http 请求以及响应
我们的上网流程大致来说是这样的:
- 我们打开浏览器,在地址栏输入我们想访问的网址,比如https://zranshi.github.io (当然你也可能从收藏夹里直接打开网站,但本质上都是一样的)
- 浏览器知道我们想要访问那个网址后,它在后台帮我们做了很多事情,主要就是把我们的访问意图包装成一个 http 请求,发给我们想要访问的网址所对应的服务器。通俗点说就是浏览器帮我们通知网站的服务器,说有人来访问你啦,访问的请求都写在 http 里了,你按照要求处理后告诉我,我再帮你回应他!
- 网站服务器处理了 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 类及其子类, 具体可以返回:
- HttpResponse 类: 返回字符串
- JsonResponse 类: 返回 Json 类型文件
- StreamingResponse 类: 流式响应,返回大的文本文件
- 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', )