安搭
软件安装搭建教程网是专门为软件开发、IT运维人员提供Apache、Centos、dotNET、Eclipse、Ftp、Git、java、mssqlserver、MySQL、Nginx、php、python、Redis、SVN、Vscode、VUE等服务器服务系统的安装教程、搭建教程、配置教程信息网。

http下载异常_荏苒项目二:配置(日志,异常,数据库,前端,跨域CORS)

内容

  • 日志配置
  • 异常配置
  • 数据库配置
  • 前端提交
  • 跨域
    • 域名
    • vim
    • axios
知乎视频​www.zhihu.com
知乎视频​www.zhihu.com

4.5 日志配置

刚搭建的web项目或者没有明确需要调用日志的系统,一般我们直接使用python提供的longging模块来配置日志功能即可。如果类似游戏或者需要对日志进行分析的系统,则一般在服务器中配置ELK日志分析系统的。

对于在django中配置的日志,那么django是没有自己实现日志功能的,而是调用了python解析器提供的日志模块loggings模块。所以,我们在settings/dev.py文件中追加如下配置:(在这之前我们在项目根目录下创建了logs文件夹)

# 日志配置
LOGGING = {
    'version': 1,
    # 是否要禁用掉已经记录的日志
    'disable_existing_loggers': False,
    # 记录日志的时候,需要记录哪些信息(文件地址,异常等级...)
    'formatters': { # 日志的处理格式
        # 详细日志
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
        },
        # format :   异常等级、日志的记录发生时间、日志在那个文件报错(位置)
        # 简单日志
        'simple': {
            'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
        },
        # format  异常等级、报错位置、 lineno、错误信息
    },
    # 过滤
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    # 日志的处理方式:eg:发邮件给我们
    'handlers': {
        # 输出到控制台
        'console': {
            'level': 'DEBUG',  # 最低等级debug,相当于所有等级的错误都显示
            'filters': ['require_debug_true'],  # 不记录
            'class': 'logging.StreamHandler',
            'formatter': 'simple'  # 输出simple格式
        },
        'file': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            # 日志位置,日志文件名,日志保存目录logs必须手动创建
            'filename': os.path.join(os.path.dirname(BASE_DIR), "logs/renran.log"),
            # 单个日志文件的最大值,这里我们设置300M(文字)
            'maxBytes': 300 * 1024 * 1024,
            # 备份日志文件的数量,设置最大日志数量为10
            'backupCount': 10,
            # 日志格式:详细格式
            'formatter': 'verbose'
        },
    },
    # 日志对象:手动记录日志
    'loggers': {
        'django': { # 固定,将来django内部也会有异常的处理,只会调用django下标的日志对象
            'handlers': ['console', 'file'],
            'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
        },
    }
}

settings.py里面的BASE_DIR

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
# 因为此时我们的项目目录结构已经发生改变,所以此时basedir代表的就是项目主目录,而不是根目录
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

配置好了以后在pyachrm的终端输入

git add .
git commit -m '日志配置'
git push
# 输入账号与密码提交到gitee里面去

v2-2ef821d423243b861de36c7187e389a8_b.jpg

可以看到码云上:

v2-4c3d02f8f4fcf0defc8866b1eecbb0fd_b.gif

4.6 异常处理

新建utils/exceptions.py

from rest_framework.views import exception_handler

from django.db import DatabaseError
from rest_framework.response import Response
from rest_framework import status

import logging
logger = logging.getLogger('django')


def custom_exception_handler(exc, context):
    """
    自定义异常处理
    :param exc: 异常类
    :param context: 抛出异常的上下文
    :return: Response响应对象
    """
    # 调用drf框架原生的异常处理方法
    response = exception_handler(exc, context)

    if response is None:
        view = context['view']
        if isinstance(exc, DatabaseError):
            # 数据库异常
            logger.error('[%s] %s' % (view, exc))
            response = Response({'message': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)

        if isinstance(exc, Exception):
            # 未知错误
            logger.error('发生未知异常,[%s] %s' % (view, exc))
            response = Response({'message': '服务器出现未知错误'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return response

settings/dev.py配置文件中添加

REST_FRAMEWORK = {
    # 异常处理
    'EXCEPTION_HANDLER': 'renranapi.utils.exceptions.custom_exception_handler',
}

配置好了以后在pyachrm的终端输入

git add .
git commit -m '异常配置'
git push
# 输入账号与密码提交到gitee里面去

4.7 创建数据库

先链接数据库 mysql -uroot -p123

create database renran default charset=utf8mb4;

为当前项目创建数据库用户[这个用户只能看到这个数据库]

# create user 用户名 identified by '登录密码';       # 创建用户

# grant 权限 on 数据库名.表名 to '用户名'@'登录主机';   # 赋予权限给用户
# * 可以表示任意数据库,也可以表示任意表,也可以表示任意登录主机
# all privileges 表示所有权限,也可以设置 单个权限或多个权限
# grant select,insert,update,delete on ....  # 只赋予增删查改的权限
# grant select on ...   # 只赋予查询权限

# flush privileges;                                # 刷新权限

create user renran_user identified by 'renran';
grant all privileges on renran.* to 'renran_user'@'*';
flush privileges;

4.8 配置数据库连接

打开settings/dev.py文件,并配置

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "USER": "renran_user",
        "PASSWORD": "renran",
        "NAME": "renran",
    }
}

在项目主模块的 __init__.py中导入pymysql

import pymysql

pymysql.install_as_MySQLdb()

调整错误

数据库版本检测导致的错误

v2-b40b5e079c3847843a522f0f42f341c3_b.jpg

数据库的版本检测代码注释掉。

v2-6bc98bf33f30910b155d3a021d5a01a7_b.jpg

因为python3版本的原因,字符串的编码问题

v2-9fabe7ca2edc018afa40bf792b2a5a39_b.jpg
把146的代码从下面改动
query = query.decode(errors='replace')
改成:
query = query.encode(errors='replace')

配置好了以后在pyachrm的终端输入

git add .
git commit -m '数据库配置'
git push
# 输入账号与密码提交到gitee里面去

5. 搭建前端项目

5.1 创建项目目录

cd 项目根目录
vue init webpack 客户端项目目录

例如,我要把项目保存在~/Desktop桌面目录下,可以如下操作:

cd ~/Desktop/renran
vue init webpack renran_pc

把vue项目构建好了,运行测试服务器。

接下来,在ubuntu使用pycharm同时通过2个窗口打开项目,一般先打开前端项目,再打开服务端项目,否则可能出现卡死的情况,此时可以先通过终端黑窗口执行以下命令,关闭pycharm,再重新先打开前端项目,接着打开后端项目。
ps aux | grep pycharm # 查看系统所有的进程ID,搜索出pycharm
kill -9 5794 # 关闭指定进程ID对应的服务。

v2-21f12bf6a7b536ae24406d3624cb4ad0_b.jpg

打开项目已经,在pycharm的终端下运行vue项目,查看效果。

npm run dev

接下来,我们根据终端上效果显示的对应地址来访问项目(如果有多个vue项目在运行,8080端口被占据了,服务器会自动改端口,所以根据自己实际在操作中看到的地址来访问。)

访问:http://locahost:8080。效果:

v2-1d2d68f905fe1c5f3c74eb18dce9d2a1_b.jpg

我们也可以把我们的前端项目进行git源代码管理

5.2 初始化前端项目

清除默认的HelloWorld组件和APP.vue中的默认样式

v2-2f39f28d69f691cd8033594a19bab8e4_b.jpg

接下来,我们可以查看效果了,一张白纸~

v2-4878d839884673fa90e14390b17a8597_b.jpg

5.3 安装路由vue-router

5.3.1 下载路由组件

如果前面没有选择安装vue-router,则使用以下命令安装路由组件:

npm i vue-router -S

执行效果:

v2-7ee595ca3ad3fc16bf7d0eb0abc87fe2_b.jpg

5.3.2 配置路由

5.3.2.1 初始化路由对象

在src目录下创建router路由目录,在router目录下创建index.js路由文件

index.js路由文件中,编写初始化路由对象的代码 .

import Vue from "vue"
import Router from "vue-router"

// 这里导入可以让让用户访问的组件

Vue.use(Router);

export default new Router({
  // 设置路由模式为‘history’,去掉默认的#
  mode: "history",
  routes:[
    // 路由列表
    {
      path: '/',
    }
  ]
})

v2-250e40be20672e84d13c86dde70839b7_b.jpg

5.3.2.2 注册路由信息

打开main.js文件,把router对象注册到vue中.代码:(/index可能不会自动添加)

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './routers/index';

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
});

v2-77668597ca0b448cd4977f3e63613782_b.jpg

5.3.2.3 在视图中显示路由对应的内容

在App.vue组件中,添加显示路由对应的内容。

v2-c9446a65b94e8e4298a7d5a0d5e28054_b.jpg

代码:

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {

  }
}
</script>

<style>

</style>

5.3.2.4 创建并提供前端首页的组件

routers/index.js

// import Vue from "vue"
// import Router from "vue-router"
//
//
// // 这里导入可以让让用户访问的组件
import Home from "../components/Home"
// Vue.use(Router);
//
// export default new Router({
//   // 设置路由模式为‘history’,去掉默认的#
//   mode: "history",
//   routes:[
//     // 路由列表
     {
       name:"Home",
       path:"/",
       component:Home,
     },
      {
       name:"Home",
       path:"/home",
       component:Home,
     },
   ]
// })

创建Home组件

components/Home.vue

<template>
  <div id="home">
    前端首页
  </div>
</template>
<script>
  export default {
      name:"Home",
      data(){
          return {

          }
      }
  }
</script>

<style scoped>

</style>

v2-dec9a77881cb44aa5ce4b1a3fa3db436_b.jpg

5.4 前端初始化全局变量和全局方法

在src目录下创建settings.js站点开发配置文件:

export default {
  Host:"http://127.0.0.1",
}

在main.js中引入

// // The Vue build version to load with the `import` command
// // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
// import Vue from 'vue'
// import App from './App'
// import router from './routers/index';
import settings from "./settings"
// Vue.config.productionTip = false;
Vue.prototype.$settings = settings;
//
// /* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });

5.5 引入ElementUI

npm i element-ui -S

上面的命令等同于

npm install element-ui --save

执行命令效果:

v2-be4b13aca81a98a3a49564d066dddd99_b.jpg

5.5.1 配置ElementUI到项目中

在main.js中导入ElementUI,并调用。

代码:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
// import Vue from 'vue'
// import App from './App'
// import router from './routers/index';

// 开发配置文件
// import settings from "./settings"
// Vue.prototype.$settings = settings;

// elementUI 导入
import ElementUI from 'element-ui';
import "element-ui/lib/theme-chalk/index.css";
// 调用插件
Vue.use(ElementUI);


// Vue.config.productionTip = false;

/* eslint-disable no-new */
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// });

效果:

v2-a571bcdf4e51cf75bca918b50f3fa738_b.jpg

重新启动项目,如果出现Error,关于.gitkeep,则直接删除这个文件即可。

成功引入了ElementUI以后,接下来我们就可以开始进入前端页面开发,首先是首页。

接下来我们把之前完成的首页,直接拿过来使用[注意除了组件以外,还有静态文件也需要拿过来,包括App.vue里面的公共样式],并运行项目。

创建static/css/reset.css,全局css初始化代码

body,h1,h2,h3,h4,h5,ul,p{
    padding: 0;
    margin:0;
    font-weight: normal;
  }
  body{
    margin-top: 80px;
  }
  a{
    text-decoration: none;
    color: #4a4a4a;
  }
  a:hover{
    color: #000;
  }
  input{
    outline: none;
  }
  ul{
    list-style: none;
  }

  img{
    width: 100%;
  }

  .header .el-menu li .el-submenu__title{
    height: 26px!important;
    line-height: 26px!important;
  }
  .el-menu--popup{
    min-width: 140px;
  }
  .el-checkbox__inner{
    width:16px;
    height: 16px;
    border: 1px solid #999;
  }
  .el-checkbox__inner:after{
    width: 6px;
    height: 8px;
  }
  .el-form-item__content{
    margin-left:0px!important;
    width: 50px;
  }
  .full-left{
    float: left;
  }
  .full-right{
    float: right;
  }

main.js

// 引入初始化样式
import "../static/css/reset.css";

Home.vue中添加代码:

<template>
  <div id="home">
    <Header></Header>
    <div class="container">
      <div class="row">
        <div class="main">
          <!-- Banner -->
          <div class="banner">
            <el-carousel height="272px" indicator-position="none" interval="2000">
              <el-carousel-item v-for="item in 4" :key="item">
                <h3 class="small">{{ item }}</h3>
              </el-carousel-item>
            </el-carousel>
          </div>
          <div id="list-container">
            <!-- 文章列表模块 -->
            <ul class="note-list">
              <li class="">
                <div class="content">
                  <a class="title" target="_blank" href="">常做此运动,让你性福加倍</a>
                  <p class="abstract">运动,是人类在发展过程中有意识地对自己身体素质的培养的各种活动 运动的方式多种多样 不仅仅是我们常知的跑步,球类,游泳等 今天就为大家介绍一种男...</p>
                  <div class="meta">
                    <span class="jsd-meta">
                      <img src="/static/image/paid1.svg" alt=""> 4.8
                    </span>
                    <a class="nickname" target="_blank" href="">上班族也健身</a>
                    <a target="_blank" href="">
                      <img src="/static/image/comment.svg" alt=""> 4
                    </a>
                    <span><img src="/static/image/like.svg" alt=""> 31</span>
                  </div>
                </div>
              </li>
              <li class="have-img">
                <a class="wrap-img" href="" target="_blank">
                  <img class="img-blur-done" src="/static/image/10907624-107943365323e5b9.jpeg" />
                </a>
                <div class="content">
                  <a class="title" target="_blank" href="">“不耻下问”,正在毁掉你的人生</a>
                  <p class="abstract">
                    在过去,遇到不懂的问题,你不耻下问,找个人问问就行;在现在,如果你还这么干,多半会被认为是“搜商低”。 昨天,35岁的表姐把我拉黑了。 表姐是医...
                  </p>
                  <div class="meta">
                    <span class="jsd-meta">
                      <img src="/static/image/paid1.svg" alt=""> 6.7
                    </span>
                    <a class="nickname" target="_blank" href="">_飞鱼</a>
                    <a target="_blank" href="">
                      <img src="/static/image/comment.svg" alt=""> 33
                    </a>
                    <span><img src="/static/image/like.svg" alt=""> 113</span>
                    <span><img src="/static/image/shang.svg" alt=""> 2</span>
                  </div>
                </div>
              </li>
            </ul>
            <!-- 文章列表模块 -->
          </div>
        <a href="" class="load-more">阅读更多</a></div>
        <div class="aside">
          <!-- 推荐作者 -->
          <div class="recommended-author-wrap">
            <!---->
            <div class="recommended-authors">
              <div class="title">
                <span>推荐作者</span>
                <a class="page-change"><img class="icon-change" src="/static/image/exchange-rate.svg" alt="">换一批</a>
              </div>
              <ul class="list">
                <li>
                  <a href="" target="_blank" class="avatar">
                    <img src="/static/image/avatar.webp" />
                  </a>
                  <a class="follow" state="0"><img src="/static/image/follow.svg" alt="" />关注</a>
                  <a href="" target="_blank" class="name">董克平日记</a>
                  <p>写了807.1k字 · 2.5k喜欢</p>
                </li>
                <li>
                  <a href="" target="_blank" class="avatar">
                    <img src="/static/image/avatar.webp" />
                  </a>
                  <a class="follow" state="0"><img src="/static/image/follow.svg" alt="" />关注</a>
                  <a href="" target="_blank" class="name">董克平日记</a>
                  <p>写了807.1k字 · 2.5k喜欢</p>
                </li>

              </ul>
              <a href="" target="_blank" class="find-more">查看全部 ></a>
              <!---->
            </div>
          </div>
        </div>
      </div>
    </div>
    <Footer></Footer>
  </div>
</template>
<script>
  import Header from "./common/Header";
  import Footer from "./common/Footer";
  export default {
      name:"Home",
      data(){
          return {

          }
      },
      components:{
        Header,
        Footer,
      }
  }
</script>

<style scoped>
.container{
    width: 960px;
    margin-right: auto;
    margin-left: auto;
    padding-left: 15px;
    padding-right: 15px;
    box-sizing: border-box;
}
.container:after, .container:before {
    content: " ";
    display: table;
}
.row {
    margin-left: -15px;
    margin-right: -15px;
}
.row:after, .row:before {
    content: " ";
    display: table;
}
.main {
    padding-top: 30px;
    padding-right: 0;
    position: relative;
    min-height: 1px;
    padding-left: 15px;
    width: 66.66667%;
    float: left;
    box-sizing: border-box;
}
.main .banner{
    width: 640px;
    height: 272px;
}
.note-list {
    margin: 0;
    padding: 0;
    list-style: none;
}
.note-list li {
    position: relative;
    width: 100%;
    margin: 0 0 15px;
    padding: 15px 2px 20px 0;
    border-bottom: 1px solid #f0f0f0;
    word-wrap: break-word;
    line-height: 20px;
}
.note-list li.have-img {
    min-height: 140px;
}
.note-list .have-img .wrap-img {
    position: absolute;
    top: 50%;
    margin-top: -60px;
    right: 0;
    width: 150px;
    height: 100px;
}
.note-list .have-img .wrap-img img {
    width: 100%;
    height: 100%;
    border-radius: 4px;
    border: 1px solid #f0f0f0;
    vertical-align: middle;
}
.main .note-list .have-img .content {
    padding-right: 165px;
    box-sizing: border-box;
}
.note-list .title {
    margin: -7px 0 4px;
    display: inherit;
    font-size: 18px;
    font-weight: 700;
    line-height: 1.5;
    color: #333;
}
.note-list .title:hover{
    text-decoration: underline;
}
.note-list .abstract {
    margin: 0 0 8px;
    font-size: 13px;
    line-height: 24px;
    color: #999;
}
.note-list .meta {
    padding-right: 0!important;
    font-size: 12px;
    font-weight: 400;
    line-height: 20px;
}
.note-list .meta span {
    margin-right: 10px;
    color: #b4b4b4;
}

.jsd-meta {
    color: #ea6f5a!important;
}
.note-list .meta a, .note-list .meta a:hover {
    transition: .1s ease-in;
}
.note-list .meta a {
    margin-right: 10px;
    color: #b4b4b4;
}
.note-list .meta img{
    width: 15px;
    vertical-align: middle;
}

.main .load-more {
    width: 100%;
    border-radius: 20px;
    background-color: #a5a5a5;
    margin: 30px auto 60px;
    padding: 10px 15px;
    text-align: center;
    font-size: 15px;
    color: #fff;
    display: block;
    line-height: 1.42857;
    box-sizing: border-box;
}
.main .load-more:hover {
    background-color: #9b9b9b;
}
.aside {
    padding: 30px 0 0;
    margin-left: 4.16667%;
    width: 29.16667%;
    float: left;
    position: relative;
    min-height: 1px;
    box-sizing: border-box;
}
.recommended-authors {
    margin-bottom: 20px;
    padding-top: 0;
    font-size: 13px;
    text-align: center;
}
.recommended-authors .title {
    text-align: left;
}
.recommended-authors .title span {
    font-size: 14px;
    color: #969696;
}
.recommended-authors .title .page-change {
    float: right;
    display: inline-block;
    font-size: 16px;
    color: #969696;
}
.icon-change{
    width: 16px;
    vertical-align: middle;
}
.recommended-authors .list {
    margin: 0 0 20px;
    text-align: left;
    list-style: none;
}
.recommended-authors .list li {
    margin-top: 15px;
    line-height: 20px;
}
.recommended-authors .list .avatar {
    float: left;
    width: 48px;
    height: 48px;
    margin-right: 10px;
}

.avatar {
    width: 24px;
    height: 24px;
    display: block;
    cursor: pointer;
}
.avatar img {
    width: 100%;
    height: 100%;
    border: 1px solid #ddd;
    border-radius: 50%;
}
.follow{
    font-size: 14px;
    color: #42c02e;
    border-color: #42c02e;
    font-weight: 400;
    line-height: normal;
}
.follow img{
    width: 14px;
}
.recommended-authors .list .follow, .recommended-authors .list .follow-cancel, .recommended-authors .list .follow-each, .recommended-authors .list .following {
    float: right;
    margin-top: 5px;
    padding: 0;
    font-size: 13px;
    color: #42c02e;
    box-sizing: border-box;
}
.recommended-authors .list .name {
    padding-top: 5px;
    margin-right: 60px;
    font-size: 14px;
    display: block;
    box-sizing: border-box;
}
.recommended-authors .list p {
    font-size: 12px;
    color: #969696;
    margin: 0 0 10px;
    box-sizing: border-box;
}
.recommended-authors .find-more {
    position: absolute;
    padding: 7px 7px 7px 12px;
    left: 0;
    width: 100%;
    font-size: 13px;
    color: #787878;
    background-color: #f7f7f7;
    border: 1px solid #dcdcdc;
    border-radius: 4px;
}
.row:after {
    clear: both;
}
.el-carousel__item h3 {
    color: #475669;
    font-size: 14px;
    opacity: 0.75;
    line-height: 150px;
    margin: 0;
}

.el-carousel__item:nth-child(2n) {
    background-color: #99a9bf;
}

.el-carousel__item:nth-child(2n+1) {
    background-color: #d3dce6;
}
</style>

main.js代码:

// iconfont字体
import "../static/css/iconfont.css";
import "../static/css/iconfont.eot";

components/common/Header.vue

<template>
  <div class="header">
    <nav class="navbar">
      <div class="width-limit">
        <!-- 左上方 Logo -->
        <a class="logo" href="/"><img src="/static/image/nav-logo.png" /></a>

        <!-- 右上角 -->
        <!-- 未登录显示登录/注册/写文章 -->
        <a class="btn write-btn" target="_blank" href="/writer"><img class="icon-write" src="/static/image/write.svg">写文章</a>
        <a class="btn sign-up" id="sign_up" href="/register">注册</a>
        <a class="btn log-in" id="sign_in" href="/login">登录</a>
        <div class="container">
          <div class="collapse navbar-collapse" id="menu">
            <ul class="nav navbar-nav">
              <li class="tab active">
                <a href="/">
                  <img class="menu-icon" src="/static/image/menu.svg">
                  <span class="menu-text">首页</span>
                </a>
              </li>
              <li class="search">
                <form target="_blank" action="/search" accept-charset="UTF-8" method="get">
                  <input type="text" name="q" id="q" value="" autocomplete="off" placeholder="搜索" class="search-input">
                  <a class="search-btn" href="javascript:void(0)"></a>
                </form>
              </li>
            </ul>
          </div>
        </div>

        <!-- 如果用户登录,显示下拉菜单 -->
      </div>
    </nav>
  </div>
</template>

<script>
    export default {
        name: "Header"
    }
</script>

<style scoped>
.header{
  height: 56px;
}
.container {
    width: 960px;
    margin-right: auto;
    margin-left: auto;
    padding-left: 15px;
    padding-right: 15px;
}
.container:after, .container:before {
    content: " ";
    display: table;
}
.container:after {
    clear: both;
}
.navbar {
    background-color: #fff;
    border-color: #f0f0f0;
    top: 0;
    border-width: 0 0 1px;
    border-radius: 0;
}
.navbar-nav {
    float: left;
    margin: 0;
}
.navbar:after, .navbar:before {
    content: " ";
    display: table;
    box-sizing: border-box;
}
.nav:after, .nav:before {
    content: " ";
    display: table;
}
nav .width-limit {
    min-width: 768px;
    max-width: 1440px;
    margin: 0 auto;
}
nav .logo {
    float: left;
    height: 56px;
    padding: 0;
}
nav .logo img {
    height: 100%;
    vertical-align: middle;
    border: 0;
}
.btn {
    display: inline-block;
    margin-bottom: 0;
    font-weight: 400;
    text-align: center;
    vertical-align: middle;
    touch-action: manipulation;
    cursor: pointer;
    background-image: none;
    border: 1px solid transparent;
    white-space: nowrap;
    padding: 6px 12px;
    font-size: 14px;
    line-height: 1.42857;
    border-radius: 4px;
}
nav .write-btn {
    float: right;
    width: 100px;
    height: 24px;
    line-height: 24px;
    margin: 8px 12px 0;
    border-radius: 20px;
    font-size: 15px;
    color: #fff;
    background-color: #ea6f5a;
    text-decoration: none;
}
nav .log-in, nav .log-in:hover {
    color: #969696;
}
nav .log-in {
    float: right;
    margin: 11px 6px 0 10px;
    font-size: 15px;
}
nav .sign-up {
    float: right;
    width: 80px;
    height: 24px;
    line-height: 24px;
    margin: 9px 5px 0 15px;
    border: 1px solid rgba(236,97,73,.7);
    border-radius: 20px;
    font-size: 15px;
    color: #ea6f5a;
    background-color: transparent;
}
nav .icon-write {
    margin-right: 3px;
    width: 19px;
    height: 19px;
    vertical-align: middle;
}
nav .menu-text{
    font-size: 17px;
    color: #ea6f5a;
}
nav .menu-icon {
    width: 20px;
    height: 20px;
    vertical-align: sub;
    margin-right: 3px;
}
nav .nav .tab a {
    height: 56px;
    line-height: 26px;
    padding: 15px;
    color: #ea6f5a;
    background: none;
}
nav .navbar-nav li {
    margin-right: 10px;
    float: left;
    position: relative;
    display: block;
    box-sizing: border-box;
    height: 56px;
    line-height: 56px;
}
.navbar-nav {
    float: left;
    margin: 0;
}
nav form {
    position: relative;
    top: 9px;
    margin: 0 0 20px;
    box-sizing: border-box;
    line-height: 20px;
}
nav form .search-input {
    padding: 0 40px 0 20px;
    height: 38px;
    font-size: 14px;
    border: 1px solid #eee;
    border-radius: 40px;
    background: #eee;
    transition: width .5s;
    width: 240px;
    outline: none;
}
nav form .search-input:focus {
    width: 320px;
    outline: none;
}
.navbar-default .navbar-collapse, .navbar-default .navbar-form {
    border-color: #e7e7e7;
    padding-left: 0;
    padding-right: 0;
    box-sizing: border-box;
    width: auto;
    border-top: 0;
    box-shadow: none;
}
.navbar {
    background-color: #fff;
    top: 0;
    border-radius: 0;
    position: fixed;
    right: 0;
    left: 0;
    z-index: 1030;
    min-height: 50px;
    margin-bottom: 20px;
    border-bottom: 1px solid #f0f0f0;
}
nav {
    height: 56px;
}
.navbar:after, .navbar:before {
    content: " ";
    display: table;
}
nav form .search-btn {
    position: absolute;
    display: block;
    top: 0;
    right: 10px;
    width: 30px;
    height: 30px;
    padding: 0;
    margin: 5px -1px 0 0;
    background: transparent url("../../../static/image/search-focus.svg") no-repeat 6px 6px;
    background-size: 20px;
}
nav form .search-input:focus~a{
    border-radius: 50%;
    background-color: #696969;
    background-image: url("../../../static/image/search-blur.svg");
}
nav .sign-up:hover {
    color: #ec6149;
    border-color: #ec6149;
    background-color: rgba(236,97,73,.05);
}
nav .write-btn:focus, nav .write-btn:hover {
    color: #fff;
    background-color: #ec6149;
}
</style>

components/common/Footer.vue

<template>
<footer class="container">
  <div class="row">
    <div class="main">
      <a target="_blank" href="">关于荏苒</a>
      <em> · </em>
      <a target="_blank" href="">联系我们</a>
      <em> · </em>
      <a target="_blank" href="">加入我们</a>
      <em> · </em>
      <a target="_blank" href="">帮助中心</a>
      <em> · </em>
      <a target="_blank" href="http://www.jianshu.com/p/cabc8fa39830">合作伙伴</a>
      <div class="icp">©2016-2019 广州荏苒信息科技有限公司 / 荏苒 / 粤ICP备16018329号-5 /</div>
    </div>
  </div>
</footer>
</template>

<script>
    export default {
        name: "Footer"
    }
</script>

<style scoped>
.container {
    width: 960px;
    margin-right: auto;
    margin-left: auto;
    padding-left: 15px;
    padding-right: 15px;
    margin-bottom: 20px;
    box-sizing: border-box;
}
.container:after, .container:before {
    content: " ";
    display: table;
}
footer .row {
    padding-top: 25px;
    box-sizing: border-box;
    margin-left: -15px;
    margin-right: -15px;
}
footer .main {
    padding-right: 0;
    font-size: 13px;
    color: #969696;
  width: 70.83333%;
}
footer .icp, footer .icp a {
    color: #c8c8c8;
}
footer .icp {
    margin-top: 10px;
    font-size: 12px;
}
footer .main a {
    color: #969696;
    display: inline-block;
}
.row:after {
    clear: both;
}
</style>

配置好了之后呢,会出现图片文件的报错信息

在服务器上部署前端项目时提示错误:Error: ENOSPC: System limit for number of file watchers.

问题原因:由于文件监视程序的系统产生了限制,达到默认上限,需要增加限额

解决方法:

首先查看当前配额

[root@js ]# cat /proc/sys/fs/inotify/max_user_watches
8192

永久增加限额

echo fs.inotify.max_user_watches = 524288 | sudo tee -a /etc/sysctl.conf 

sudo sysctl -p

然后就不会报错了

6. 跨域CORS

在网络中,我们要访问一台电脑必须要知道对方的IP,但是IP基本上由数字构成,所以不方便记忆。因此,有了域名。域名的出现就为了方便人们记忆对应的电脑(服务器)IP的。

域名一般分国际域名与区域域名:
   常见的国际域名:net,com,org,...
   常见的地区域名:cn,hk,gd,bj... 

域名的结构:三级地址.二级地址.域名名称.供应商

顶级域名:
   baidu.com
   qq.com

二级域名:
   www.baidu.com
   mail.qq.com
三级域名:
   user.wx.qq.com
   laonanhai.tiebai.baidu.com

域名就跟QQ一样,我们需要购买期限的,一般按年购买,无法永久买。

在公网中,我们之所以可以通过域名直接访问到对应的电脑,主要原因是因为我们对于域名进行了解析,所买回来的域名,务必要解析到对应的服务器才能使用。同时,一旦我们对域名进行了解析,等同于在公网的域名解析服务器[DNS]里面把IP和域名进行了绑定。

我们现在为前端和后端分别设置两个不同的域名:

| 位置 | 域名          | | ---- | ------------- | 
| 前端 | www.moluo.net | | 后端 | api.renran.cn |

编辑/etc/hosts文件,可以设置本地域名

sudo vim /etc/hosts
通过在终端输入命令: vim  文件名   表示创建或者打开一个文件
vim有三种操作模式:
快捷键模式:刚打开文件,窗口左下角最底下一行什么内容都没有,则表示当前处于快捷键模型。
          这种模式,我们要控制编辑器,只能通过vim提供的快捷键,无法使用鼠标。
          dd 表示剪切当前光标所在的一行内容
          p  表示把复制的内容粘贴到光标的下一行

编辑模式:  在快捷键模式中,通过按键i/a/A/I/O/o进入,其中i表示插入,a表示追加,o表示下一行新增内容
          要退出编辑模式,使用按键Esc[复位键]即可返回快捷键模式

命令行模式:在快捷键模式中,通过shift+:进入
          要退出命令行模式,也是使用按键Esc.
          :set nu   # 显示文件行号
          :w        # 保存文件的修改
          :q        # 退出当前操作文件,关闭编辑器
          :wq       # 保存并退出
          :wq!      # 强制保存退出

在文件中增加两条信息

127.0.0.1   api.renran.cn
127.0.0.1   www.moluo.net

v2-c6e25dd7b830d900a562633ddb39bf63_b.jpg

访问网址http://api.renran.cn:8000,效果正常,原因是我们在settings/dev.py里面设置了访问名单为*

v2-66c0888b1c6f1c121c68adeccef60630_b.png

访问效果:

v2-09c0362ece3fb0773e41bdf0287ef2b8_b.jpg

让用户访问的时候,使用http://api.renran.cn:8000

接下来访问前端http://www.moluo.net:8080/,效果如下:

v2-f8da451401173fbf08a2c0e9de9c14a6_b.jpg

上面并不是配置错误,而是没人监听了这个地址和端口了,解决方法:

暂停运行前端项目,并修改配置文件config/index.js

host: 'www.moluo.net', // 这里配置域名
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: true,

保存修改信息,并重启vue项目

现在,前端与后端分处不同的域名,我们需要为后端添加ajax跨域访问的支持

否则前端无法使用axios请求后端提供的api数据,我们使用CORS来解决后端对跨域访问的支持。

使用django-cors-headers扩展

在 Response(headers={"Access-Control-Allow-Origin":'客户端地址/*'})

文档:https://github.com/ottoyiu/django-cors-headers/

安装

pip install django-cors-headers

settings/dev.py,添加应用

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)

中间层设置【必须写在第一个位置】

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
    # 'django.middleware.csrf.CsrfViewMiddleware', # 注释这个中间件
]

添加客户端跨域的白名单

# CORS组的配置信息
CORS_ORIGIN_WHITELIST = (
    'http://www.moluo.net:8080',
)
CORS_ALLOW_CREDENTIALS = False  # 不允许ajax跨域请求时携带cookie

v2-9bd60745e64946cc57662f299a6cdbf0_b.jpg

v2-8a1ce2cab2860ceca980e045e12fb411_b.jpg

完成了上面的步骤,我们就可以通过后端提供数据给前端使用ajax访问了。

前端使用 axios就可以访问到后端提供给的数据接口,但是如果要附带cookie信息,前端还要设置一下。

前端引入axios插件并配置允许axios发送cookie信息[axios本身也不允许ajax发送cookie到后端]

cd renran_pc/
npm i axios -S

v2-622cc1cb827aa20a8d1f224de128f96d_b.jpg

在main.js中引用 axios插件

import axios from 'axios'; // 从node_modules目录中导入包

// 允许ajax发送请求时附带cookie,设置为不允许
axios.defaults.withCredentials = false;

Vue.prototype.$axios = axios; // 把对象挂载vue中

文章来源:https://blog.csdn.net/weixin_39872334/article/details/109907174