94、下单接口前端、前端get回调和支付宝post回调、扫码登陆、部署项目、127.0.0.1与0.0.0.0区别

205 阅读9分钟

今日内容概要

  • 下单接口前端

  • 前端get回调和支付宝post回调

  • 扫码登陆功能

  • 上线前准备

  • 阿里云购买

  • 安装git

  • 安装mysql

  • 安装redis

  • 安装python

  • 安装虚拟环境

  • 安装uwsgi

  • 安装nginx

  • 部署前端项目

  • 部署后台项目

  • 安全组

  • 127.0.0.1与0.0.0.0区别

今日内容详细

补充

设置jwt过期时间

import datetime
JWT_AUTH = {
    # 过期时间7天
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),

}

支付宝支付流程

在咱们前端,点击购买(下单)---->咱们后端发送请求----->到咱们后端,把携带的商品信息,入库(订单库)--->生成的支付链接,返回给前端---->前端拿到支付链接--->打开支付链接--->看到支付宝付款页面--->手机扫描付款,直接输入用户名密码付款---->付款成功,支付宝收到了----->让前端回调回咱们的前端(配置)(get回调)---->等待支付宝post回调(回调后端,配置)--->这个回调中验签--->修改订单状态--->过程结束
    

location.search

JavaScript中,location.search 是一个包含当前页面 URL 查询参数的字符串。当浏览器加载一个 URL 时,查询参数是 URL 中问号(?)后面的部分,包含一个或多个键值对。location.search 返回的字符串包括问号(?)以及后面的所有查询参数。

//假设当前页面 URL 是 https://www.example.com/?name=John&age=25

// 创建 URLSearchParams 对象
var params = new URLSearchParams(location.search);

// 获取特定查询参数的值
var name = params.get('name');
console.log(name); // 输出: John

var age = params.get('age');
console.log(age); // 输出: 25

substring()

location.search.substring(1) 是将 location.search 字符串的第一个字符(问号?)去除后的子字符串。

在 JavaScript 中,substring() 方法用于提取字符串中指定范围的子字符串。该方法接受两个参数:起始索引和结束索引(可选)。如果省略结束索引,则提取从起始索引到字符串末尾的所有字符。

在这种情况下,location.search 是一个包含查询参数的字符串,例如 ?name=John&age=25。通过调用 substring(1),我们从第一个字符开始提取子字符串,也就是去除了第一个字符的 name=John&age=25

下单接口前端

CourseDetail.vue

              <button class="buy-now" @click="HandelGoPay">立即购买</button>

HandelGoPay() {
  //1.判断登陆没有
  let token = this.$cookies.get('token')
  if (!token){
    this.$message('请登录再购买哦')
    return
  }
  //2.发送请求
  const config={
    headers:{
      Authorization:'jwt '+token
    }
  }

  this.$axios.post(`${this.$settings.BASE_URL}order/pay/`, {
    "subject": this.course_info.name,
    "total_amount": this.course_info.price,
    "pay_type": 1,
    "courses": [this.course_info.id]
  },config).then(res=>{
    if (res.data.code==100){
      //获取pay_url
      const pay_url=res.data.pay_url
      open(pay_url,'_self')

    }else {
      //获取失败
      this.$message('下单失败')
    }
  })
},

前端get回调和支付宝post回调

前端get回调

前端回调页面

<template>
    <div class="pay-success">
        <!--如果是单独的页面,就没必要展示导航栏(带有登录的用户)-->
        <Header/>
        <div class="main">
            <div class="title">
                <div class="success-tips">
                    <p class="tips">您已成功购买 1 门课程!</p>
                </div>
            </div>
            <div class="order-info">
                <p class="info"><b>订单号:</b><span>{{ result.out_trade_no }}</span></p>
                <p class="info"><b>交易号:</b><span>{{ result.trade_no }}</span></p>
                <p class="info"><b>付款时间:</b><span><span>{{ result.timestamp }}</span></span></p>
            </div>
            <div class="study">
                <span>立即学习</span>
            </div>
        </div>
    </div>
</template>

<script>
    import Header from "@/components/Header"

    export default {
        name: "Success",
        data() {
            return {
                result: {},
            };
        },
        created() {
            // url后拼接的参数:?及后面的所有参数 => ?a=1&b=2
            // console.log(location.search);
            //http://127.0.0.1:8080/pay/success?charset=utf-8&out_trade_no=f1692dff-26ed-431b-be92-b76b76fa52c0&method=alipay.trade.page.pay.return&total_amount=199.00&...

            // 解析支付宝回调的url参数
            let params = location.search.substring(1);  // 去除? => a=1&b=2
            let items = params.length ? params.split('&') : [];  // ['a=1', 'b=2']
            //逐个将每一项添加到args对象中
            for (let i = 0; i < items.length; i++) {  // 第一次循环a=1,第二次b=2
                let k_v = items[i].split('=');  // ['a', '1']
                //解码操作,因为查询字符串经过编码的
                if (k_v.length >= 2) {
                    // url编码反解
                    let k = decodeURIComponent(k_v[0]);
                    this.result[k] = decodeURIComponent(k_v[1]);
                    // 没有url编码反解
                    // this.result[k_v[0]] = k_v[1];
                }

            }
            // 解析后的结果
            console.log(this.result);


            // 把地址栏上面的支付结果,再get请求转发给后端
            this.$axios({
                url: this.$settings.BASE_URL + '/order/success/' + location.search,
                method: 'get',
            }).then(response => {
                console.log(response.data);
            }).catch(() => {
                console.log('支付结果同步失败');
            })
        },
        components: {
            Header,
        }
    }
</script>

<style scoped>
    .main {
        padding: 60px 0;
        margin: 0 auto;
        width: 1200px;
        background: #fff;
    }

    .main .title {
        display: flex;
        -ms-flex-align: center;
        align-items: center;
        padding: 25px 40px;
        border-bottom: 1px solid #f2f2f2;
    }

    .main .title .success-tips {
        box-sizing: border-box;
    }

    .title img {
        vertical-align: middle;
        width: 60px;
        height: 60px;
        margin-right: 40px;
    }

    .title .success-tips {
        box-sizing: border-box;
    }

    .title .tips {
        font-size: 26px;
        color: #000;
    }


    .info span {
        color: #ec6730;
    }

    .order-info {
        padding: 25px 48px;
        padding-bottom: 15px;
        border-bottom: 1px solid #f2f2f2;
    }

    .order-info p {
        display: -ms-flexbox;
        display: flex;
        margin-bottom: 10px;
        font-size: 16px;
    }

    .order-info p b {
        font-weight: 400;
        color: #9d9d9d;
        white-space: nowrap;
    }

    .study {
        padding: 25px 40px;
    }

    .study span {
        display: block;
        width: 140px;
        height: 42px;
        text-align: center;
        line-height: 42px;
        cursor: pointer;
        background: #ffc210;
        border-radius: 6px;
        font-size: 16px;
        color: #fff;
    }
</style>

后端:前端回调get请求

from rest_framework.viewsets import GenericViewSet
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
class  PayOrderView(GenericViewSet):
    serializer_class = OlderSerializer
    authentication_classes = [JSONWebTokenAuthentication]
    permission_classes = [IsAuthenticated]
    def create(self,request,*args,**kwargs):

        ser = self.get_serializer(data = request.data,context={"request":request})
        ser.is_valid(raise_exception=True)
        ser.save()
        pay_url = ser.context.get('pay_url')
        return APIResponse(pay_url=pay_url)


from rest_framework.viewsets import ViewSet
from .models import Order
class SuccessView(ViewSet):
    def get(self,request,*args,**kwargs):
        # 根据订单号,查看是否是是一直已经支付的状态
        try:
            out_trade_no= request.query_params.get('out_trade_no')
            Order.objects.get(order_status=1,out_trade_no=out_trade_no)
            return APIResponse()
        except Exception as e:
            return APIResponse(code=101,msg='订单没有支付')

路由

from .views import SuccessView
urlpatterns = [
    path('success/', SuccessView.as_view({'get':'get','post':'post'})),
]

支付宝post回调

1.因为我们的地址是 127.0.0.1 ,支付宝回调,只能回调公网地址,调不回我们这,我们收不到支付宝的回调--->解决方案:
	1.使用公网ip部署项目 
  2.使用内网穿透
	内网穿透文档:https://zhuanlan.zhihu.com/p/370483324
  	原理:转发-->支付宝向某个域名(随机生成)把请求发送给  花生壳 --->根据请求知道是哪台内网机器---->把网络请求,转发给你 

视图类

from rest_framework.viewsets import ViewSet
from .models import Order
from utils.common_logger import logger
from rest_framework.response import Response
class SuccessView(ViewSet):
    def get(self,request,*args,**kwargs):
        ...
        
    def post(self,request,*args,**kwargs):
        try:
            result_data = request.data.dict()  # 支付宝发送post请求给我们--->数据携带再请求体中--->urlencoded-->request.data不是字典格式,使用dict做成字典格式
            out_trade_no = result_data.get('out_trade_no')
            signature = result_data.pop('sign')
            from libs.alipay_common import alipay
            result = alipay.verify(result_data, signature)  # 验签通过表示是支付宝给的,不是别人伪造的
            # trade_status 确认订单付款成功了
            if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
                # 完成订单修改:订单状态、流水号、支付时间
                Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1)
                # 完成日志记录
                logger.warning('%s订单支付成功' % out_trade_no)
                return Response('success')  # 必须这样,不能有别的东西
            else:
                logger.error('%s订单支付失败' % out_trade_no)
        except:
            pass
        return Response('failed')
wlguwg8538@sandbox.com

扫码登陆功能

逻辑

1.网站上,点击扫码登录---->弹出二维码
	向后端发送请求---->后端生成二维码--->返回--->前端显示了--->放了个链接地址
    
2.掏出手机,打开对应的app---->扫描二维码---->app能解析出这个地址---->取出你当前app登录的token---->向这个地址发送请求,携带token
	后端有个携带token请求登录的接口
  后端接口:拿到请求传入的token,解析出当前用户---->签发token---->找个地方存着
    
3.网站上,开启了定时任务,不停的向后端发送请求---->查询有没有我让它签发token
		一旦发现没有,过一会在发,3分钟内不停的发
    一旦发现有,携带回来---》token---》前端就登录成功了
    
3.后端接口
	1.生成二维码接口
  2.手机携带token,得到用户,再签发token的接口
  3.网站获取token接口
    
4.前端
	1.二维码页面
  2.定时任务

真实逻辑

1.前端
	1.进入扫码登录页面---->向后端发送请求,获取一个验证码图片,显示在前端
		把key:1234567暂存
	2.掏出手机扫码--->用自己的app--->扫码--->app端提示是否登录--->当你点登录--->向二维码链接地址发送请求--->http://192.168.1.252:8000/api/v1/user/qrlogin/login/?key=1234567&token=sss
	3.启动定时任务,隔一会向后端发送一个查询是否登录的请求--->
http://192.168.1.252:8000/api/v1/user/check_login/?key=123456
	4.根据key,有没有签发的token,如果有直接带回来,token,username--->登录成功了
    如果没有,过一会在发,5分钟以后就不做了

    
2.后端
   1.获取验证码图片接口--->验证码图片放链接地址:http://192.168.1.252:8000/api/v1/user/qrlogin/login/?key=123456,图片的地址中也有这个key   		{url:base64,key:123456}
    	 -http://192.168.1.252:8000/api/v1/user/qrlogin/login/?user_id=1&key=1234567
	2.扫码登录接口---->取出用户的token,认证---->根据当前用户签发token--->根据放在某个位置待命---{123456唯一:value}
        
	3.查询是否签发token的接口,根据key

后端

from rest_framework.viewsets import ViewSet
import qrcode
from io import BytesIO
import base64
from rest_framework_jwt.settings import api_settings
from django.core.cache import cache

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class QRlogin(ViewSet):
    @action(methods=['GET'],detail=False)
    def scan(self,request,*args,**kwargs):
        img = qrcode.make('http://127.0.0.1:8000/api/v1/user/qrlogin/login/?user_id=1')
        img = img.get_image()
        b= BytesIO()
        img.save(b,format="JPEG")
        res = base64.b64encode(b.getvalue())
        return APIResponse(url=res,user_id = 1)
    @action(methods=['POST'],detail=False)
    def login(self,request,*args,**kwargs):
        user_id = request.query_params.get('user_id')
        user = User.objects.get(pk= user_id)
        # 签发token,放到redis
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        user_info={"username":user.username,"token":token}
        import time
        time.sleep(5)
        cache.set('user_id_%s' % user_id, user_info)
        return APIResponse()

    @action(methods=['GET'], detail=False)
    def check_login(self,requests,*args,**kwargs):
        user_id = requests.GET.get('user_id')
        user_info = cache.get('user_id_%s' % user_id)
        if user_info:
            cache.set('user_id_%s' % user_id, None)
            return APIResponse(token=user_info.get('token'), username=user_info.get('username'))
        else:
            return APIResponse(code=101, msg='手机端尚未确认登录')

路由

from django.urls import path
from .views import UserView,RedisTest,SetPassword,SckillView,QRlogin
from rest_framework.routers import SimpleRouter
from rest_framework_jwt.views import obtain_jwt_token
router = SimpleRouter()
router.register('userinfo',UserView,'userinfo')
router.register('setpassword',SetPassword,'setpassword')
router.register('qrlogin',QRlogin,'qrlogin')

urlpatterns = [
# path('test/',RedisTest.as_view())
path('skill/',SckillView.as_view())
]
urlpatterns +=router.urls

前端



<template>
  <div>

    <img :src="url" alt="">

  </div>

</template>
<script >
import el from "element-ui/src/locale/lang/el";

export default {
  data(){
    return{
      url:'',
      user_id: '',
      t:null
    }
  },
  created() {
    this.$axios.get(`${this.$settings.BASE_URL}user/qrlogin/scan/`).then(res=>{
      if (res.data.code==100){
        //打开二维码,扫码login,开定时器
        this.url ='data:image/jpg;base64,'+ res.data.url
        this.user_id = res.data.user_id
        //开启定时任务
        this.t = setInterval(()=>{
          this.$axios.get(`${this.$settings.BASE_URL}user/qrlogin/check_login/?user_id=`+this.user_id).then(res=>{
            if (res.data.code==100){
              this.$cookies.set('token',res.data.token,'7d')
              this.cookies.set('username',res.data.username,'7d')
              clearInterval(this.t)
              this.t = null
              this.$router.push('/')
            }else{
              this.$message({
              message: res.data.msg,
              type: 'warning'
            });
            }

          })
        },3000)
      }
    })
  }
}

</script>

<style scoped>

</style>

阿里云购买

1.购买一台服务
	1.项目跑在服务器上
  2.购买公网ip:别人访问我们的ip,就能访问到我们的项目
  3.购买域名:备案--->访问域名--->转发到你的ip

2.阿里云,华为云,腾讯云
	按量付费--->冲100块--->买4台
  阿里云云服务器:https://ecs.console.aliyun.com/home
    
3.下载 finalshell(xshell收费) ,远程链接linux服务器的
	http://www.hostbuf.com/t/988.html
  不下这个软件:打开cmd :ssh root@8.130.18.221    输入密码
    一堆linux命令

上线前准备

后端项目

修改好线上配置文件,把代码推送到git仓库

1.将配置文件中的dev.py内容复制到prod.py
2.修改配置文件内容
	1.修改debug模式
    DEBUG = False
    ALLOWED_HOSTS = ['*']
    
  2.修改前台基URL,后台基URL
		LUFFY_URL = 'http://47.111.10.23'  # 47.111.10.23是在阿里云服务器上购买的公网ip地址
		BACKEND_URL="http://47.111.10.23:8000"
    
3.代码推送到git仓库

前端项目

1.修改前端访问的后端地址
    export default {
        BASE_URL:'http://47.111.10.23:8000/api/v1/'
    }
2.把vue项目编译成 html,css,js
    1.命令:npm run build  # 在项目目录下生成dist文件夹,内部就是咱们上线要用的
    2.把dist文件夹压缩,待命
wlguwg8538@sandbox.com

上线架构图

上线架构图.png

购买服务器

1.购买阿里云服务器
2.短期或是测试使用,创建 按量收费 服务器,可以随时删除,删除后不再计费,但要保证账户余额100元以上

连接服务器

1.账号
	ssh root@47.111.10.23

2.密码
>: ********

服务器命令

管理员权限
1)以下所有的服务器命令均可以在管理员权限下执行
>: sudo 命令
配置终端
1)编辑配置文件
>: vim ~/.bash_profile

2)将原来内容全部删除掉
>: ggdG

3)进入编辑状态:填入下方两行
>: i

export PATH=$PATH:$HOME/bin
PS1='Path:\w\n>:'

4)退出编辑状态
>: esc

5)保存修改并退出
>: :wq

6)生效配置
>: source ~/.bash_profile

安装git

更新系统软件包
>: yum update -y
1.方式一:
	yum install git -y
    
2.方式二:(开发会用的软件)
	yum -y groupinstall "Development tools"
	
3.执行下面这条
	yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel psmisc libffi-devel -y
  
4.检测是否成功:会将git作为依赖安装号:
  git

安装mysql

安装mysql 5.7 

2.前往用户根目录
 cd ~

3.下载mysql57
wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm

4.安装mysql57
 yum -y install mysql57-community-release-el7-10.noarch.rpm
 yum install mysql-community-server --nogpgcheck -y

5.启动mysql57并查看启动状态
  systemctl start mysqld
  systemctl status mysqld

6.查看默认密码并登录
  grep "password" /var/log/mysqld.log   # ,3QRakjs+EU/
  mysql -uroot -p

7.修改密码
 ALTER USER 'root'@'localhost' IDENTIFIED BY 'Lqz12345?';

安装redis

官方下载编译好的reids

1.下载
	wget https://packages.redis.io/redis-stack/redis-stack-server-6.2.6-v7.rhel7.x86_64.tar.gz
2.解压安装包
	tar -xf redis-stack-server-6.2.6-v7.rhel7.x86_64.tar.gz
3.移动到redis
	mv redis-stack-server-6.2.6-v7/ redis
4.切换到redis下的bin文件夹
	cd redis/bin
5.启动redis
	./redis-server   # 启动redis,使用默认配置启动的


2.需求:在任意路径下敲redis-server都能把服务运行,
	1.方式一:把bin路径加入到环境变量
	2.方式二:使用软连接-->/usr/bin/本身在环境变量,在任意路径敲redis-server redis-cli都能找到 
    ln -s /root/redis/bin/redis-server /usr/bin/redis-server
    ln -s /root/redis/bin/redis-cli /usr/bin/redis-cli
    
  2.1 查看是否创建软连接成功
  	ls |grep redis

	2.2 启动redis服务,后台运行
		redis-server &



源码安装

1.下载redis-6.2.6
	wget http://download.redis.io/releases/redis-6.2.6.tar.gz

2.解压安装包
	tar -xf redis-6.2.6.tar.gz

3.进入目标文件
	cd redis-6.2.6

4.编译环境gcc,在src路径下把源码编译出redis-cli、reidis-server
 	make   

5.复制环境到指定路径完成安装
	cp -r ~/redis-6.2.6 /usr/local/redis

6.配置redis可以后台启动:修改下方内容
  vim /usr/local/redis/redis.conf
  daemonize yes

7.完成配置修改
>: esc
>: :wq

8.建立软连接
ln -s /usr/local/redis/src/redis-server /usr/bin/redis-server1
ln -s /usr/local/redis/src/redis-cli /usr/bin/redis-cli1

9.后台运行redis
>: cd /usr/local/redis
>:  redis-server1 ./redis.conf

10.测试redis环境
	redis-cli

11.关闭redis服务
	pkill -f redis -9
	redis-cli  shutdown

安装python

1.安装python
  1.可以使用yum 安装,不能指定版本
  2.源码安装,下载指定版本的源码,编译安装
	3.所有linxu和mac,都自带python2:系统服务,是用python写的
	4.阿里云的centos默认装了python3.6.8
	5.python2.7     python3.6.8     python3.9


1.源码安装python,依赖一些第三方zlib* libffi-devel
yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel psmisc libffi-devel zlib* libffi-devel  -y

1.前往用户根目录
cd ~

2.下载 或 上传 Python3.8.6  服务器终端
# https://registry.npmmirror.com/binary.html?path=python/
# wget https://registry.npmmirror.com/-/binary/python/3.8.6/Python-3.8.6.tgz
wget https://registry.npmmirror.com/-/binary/python/3.9.10/Python-3.9.10.tgz
# wget https://www.python.org/ftp/python/3.9.16/Python-3.9.16.tgz

3.解压安装包
tar -xf Python-3.9.10.tgz 

4.进入目标文件
cd Python-3.9.10

5.配置安装路径:/usr/local/python3
	把python3.9.10 编译安装到/usr/local/python38路径下
./configure --prefix=/usr/local/python39

6.编译并安装,如果报错,说明缺依赖
yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel psmisc libffi-devel zlib* libffi-devel  -y

7.make &&  make install

7.建立软连接:/usr/local/python38路径不在环境变量,终端命令 python3,pip3
ln -s /usr/local/python39/bin/python3 /usr/bin/python3.9
ln -s /usr/local/python39/bin/pip3 /usr/bin/pip3.9

8.机器上有多个python和pip命令,对应关系如下
  python       2.x      pip 
  python3      3.6      pip3
  python3.9    3.9      pip3.9

#8  删除安装包与文件:
rm -rf Python-3.9.10
rm -rf Python-3.9.10.tar.xz

安装虚拟环境

1.安装依赖
	pip3.9 install virtualenv
# python3.9 -m pip install --upgrade pip
# python3.9 -m pip install --upgrade setuptools
# pip3.9 install pbr
>: pip3.9 install virtualenvwrapper
"""
cd /usr/local/python39/bin
ls
>>>virtualenv

"""

2.建立虚拟环境软连接
>: ln -s /usr/local/python39/bin/virtualenv /usr/bin/virtualenv

3.配置虚拟环境:填入下方内容
# ~/ 表示用户家路径:root用户,就是在/root/.bash_profile
>: vi ~/.bash_profile  
# 按 a
# 光标上下控制,粘贴上下面内容

VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3.9
source /usr/local/python39/bin/virtualenvwrapper.sh
# 按 esc
# 输入  :wq   敲回车


# 退出编辑状态
esc

# 保存修改并退出
>: :wq

4.更新配置文件内容
source ~/.bash_profile

5.虚拟环境默认根目录:/root/.virtualenvs


6.创建虚拟环境
mkvirtualenv -p python3.9 luffy

安装uwsgi

1.django项目上线需要使用uwsgi这个web服务器运行django项目,安装这个web服务器
2.使用uwsgi运行django,不再使用测试阶段的wsgiref来运行django了
3.uwsgi是符合wsgi协议的web服务器,使用c写的性能高,上线要使用uwsgi

4.安装步骤
	1.在真实环境下安装
	pip3.9 install uwsgi
	ps:安装到了python39的安装路径的bin路径下了
  """
  cd /usr/local/python39/bin
  ls
  >>>uwsgi
  """
	2.建立软连接
	ln -s /usr/local/python39/bin/uwsgi /usr/bin/uwsgi

安装nginx

1.反向代理服务器
	1.做请求转发 
  2.静态资源代理
  3.负载均衡
    
1.前往用户根目录
cd ~

2.下载nginx1.13.7
 wget http://nginx.org/download/nginx-1.13.7.tar.gz

3.解压安装包
tar -xf nginx-1.13.7.tar.gz

4.进入目标文件
cd nginx-1.13.7

5.配置安装路径:/usr/local/nginx
./configure --prefix=/usr/local/nginx

6.编译并安装
 make &&  make install

7.建立软连接:终端命令 nginx
ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx

8.删除安装包与文件:
cd ~
rm -rf nginx-1.13.7
rm -rf nginx-1.13.7.tar.xz

9.测试Nginx环境,服务器运行nginx,本地访问服务器ip
nginx   # 启动nginx服务,监听80端口---->公网ip 80 端口就能看到页面了
服务器绑定的域名 或 ip:80
"""
http://47.111.10.23/----->不写默认80端口
"""

10.静态文件放的路径:/usr/local/nginx/html

11.查看进程 
ps aux | grep nginx

部署前端项目

1.dist.zip 文件,在本地,上传到远程服务器
## html文件中
1.在远程服务器上
yum install lrzsz -y   # 跟本地机器上传下载的软件
yum install unzip -y    #解压zip软件

2.在远程服务器上
rz  # 打开你本地的目录,选中dist.zip  上传到远端
"""
mac终端执行的不可上传到远端,输入以下(mac本地终端输入)
scp Desktop/dist.zip root@47.111.10.23:~

scp /path/to/example.txt username@remotehost:/home/username
例如,如果你要上传的文件是位于你的本地电脑的/path/to/example.txt,远程服务器的用户名是username,主机名或IP地址是remotehost,上传到远程服务器的目录是/home/username
"""

3.解压
unzip dist.zip

4.移动文件  /home/html  下面有咱们的前端静态文件
mv /root/dist /home/html
    
5.配置nginx 静态代理
cd  /usr/local/nginx/conf   # nginx.conf   配置文件
mv nginx.conf nginx.conf.bak
vi nginx.conf
# 按 a  粘贴下面代码
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    server {
        listen 80;
        server_name  127.0.0.1;
        charset utf-8;
        location / {
            root /home/html;
            index index.html;
            try_files $uri $uri/ /index.html;
        }
    }
} 
# 按 esc  :wq  回车

6.重启nginx
nginx -s reload

部署后台项目

1.本地
	1.prod.py 配置文件搞好,上午搞了
	2.修改项目中wsgi.py,asgi.py  用uwsgi运行wsgi.py
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.prod')
	3.导出项目依赖
    pip3 freeze > requirements.txt
	4.推到远端

2.远程服务器
	1.拉取项目,安装模块
    mkdir /home/project
    cd  /home/project
    git clone https://gitee.com/luona-cx/luffy_api.git
    
	2.进入到虚拟环境
    workon luffy 
    cd /home/project/luffy_api
    pip install -r requirements.txt  # 可能会出错 mysqlclient装不上,先注释,装上能装上的,再单独装mysqlclient

    yum install python3-devel -y
    yum install mysql-devel --nogpgcheck -y
    pip install mysqlclient


	2.虚拟环境中也要安装uwsgi
    pip install uwsgi
    

配置数据库

mysql -uroot -p
1.创建数据库
create database luffy default charset=utf8;

2.设置权限账号密码:账号密码要与项目中配置的一致
grant all privileges on luffy.* to 'luffy'@'%' identified by 'Luffy123?';
grant all privileges on luffy.* to 'luffy'@'localhost' identified by 'Luffy123?';
flush privileges;
3.退出mysql
	quit;
4.使用本地navicate链接阿里云的luffy库,使用luffy用户

迁移表

1.把项目中得迁移文件删除,提交,远程
	python manage.py makemigrations
	python manage.py migrate
  
  ps:在本地luffy中把apps中的migrations中的00x删除
"""
  python manage_prod.py makemigrations
	python manage_prod.py migrate
"""

uwsgi 运行django

1.写一个uwsgi的配置文件,在项目路径下,新建一个  luffyapi.xml
	>>>vi luffyapi.xml
  
        <uwsgi>    
           <socket>127.0.0.1:8888</socket>
           <chdir>/home/project/luffy_api/</chdir>       
           <module>luffy_api.wsgi</module>
           <processes>4</processes>
           <daemonize>uwsgi.log</daemonize>
    	</uwsgi>
      
2.使用uwsgi启动
	uwsgi -x luffyapi.xml
3.查看是否正常运行
	ps aux |grep uwsgi
  
4.补充
	以下是uwsgi与nginx的通信手段,三选一即可
	1.选项1, 使用unix socket与nginx通信,仅限于uwsgi和nginx在同一主机上情形
		Nginx配置中uwsgi_pass应指向同一socket文件
    socket=/run/uwsgi/%(project).sock
	2.选项2,使用TCP socket与nginx通信
		Nginx配置中uwsgi_pass应指向uWSGI服务器IP和端口
		socket=0.0.0.0:8888 或则 socket=:8000
	3.选项3,使用http协议与nginx通信
		Nginx配置中proxy_pass应指向uWSGI服务器一IP和端口
		http=0.0.0.0:8888 
    location / {
      include uwsgi_params;
      uwsgi_pass 127.0.0.1:8888;
      uwsgi_param UWSGI_SCRIPT luffy_api.wsgi; 
      uwsgi_param UWSGI_CHDIR /home/project/luffy_api/;   # 用选项1,2,接收不了http请求,性能高,更接近于底层

      proxy_pass http://127.0.0.1:8888; # # 用选项3
    }
            

补充:127.0.0.1与0.0.0.0区别

1.软件运行,监听地址
	127.0.0.1:只能访问 127.0.0.1  localhost ,不能用本机ip地址访问,外部所有人都不能 访问你

	0.0.0.0127.0.0.1 localhost 本机ip地址访问  同一个局域网内,都可以通过ip地址访问 

    
2.本地host解析
	输入网址---》www.baidu.com---->找本地host文件---》找跟ip地址的对应关系----》找到直接访问这个ip地址----如果找不到---->用你配置的dns解析

配置nginx转发

1.
  cd /usr/local/nginx/conf
  vi nginx.conf
2.新增的server
  server {
    listen 8000;
    server_name  127.0.0.1;
    charset utf-8;
    location / {
      include uwsgi_params;
      uwsgi_pass 127.0.0.1:8888;
      uwsgi_param UWSGI_SCRIPT luffy_api.wsgi; 
      uwsgi_param UWSGI_CHDIR /home/project/luffy_api/;
    }
  }
        
3.重启nginx 
` nginx -s reload

导入数据


1.此处为了简便,将原来的数据,直接转储sql文件(结构和数据)
2.将远程的luffy数据库直接运行sql文件
ps:实际上,是直接添加数据

配置域名解析

购买

配置后台admin访问

1.浏览器访问http://47.111.10.23:8000/admin  发现没有样式
	因为uwsgi不能给我们代理静态资源--->debug =False--->不能转发静态资源了
	收集静态资源,使用nginx代理
  
2.prod.py中加入
"""
cd /home/project/luffy_api/luffy_api/settings
 vi prod.py
"""
	
  STATIC_ROOT = '/home/project/luffy_api/luffy_api/static/'

3.执行命令
	1.进入虚拟环境
  mkdir /home/project/luffy_api/luffy_api/static
  python manage_prod.py collectstatic
  
  
  """

 cd  /home/project/luffy_api/luffy_api/static
 ls 
 >>>admin  rest_framework
  """

	2.修改nginx配置文件
  cd /usr/local/nginx/conf
  vi nginx.conf
  
	3.新增的配置静态文件

    server {
                listen 8000;
                server_name  127.0.0.1;
                charset utf-8;
                location / {
                   include uwsgi_params;
                   uwsgi_pass 127.0.0.1:8888;
                   uwsgi_param UWSGI_SCRIPT luffy_api.wsgi; 
                   uwsgi_param UWSGI_CHDIR /home/project/luffy_api/;
                }
               location /static {
                alias /home/project/luffy_api/luffy_api/static;
              }
            }
    
 4.重启nginx
	nginx -s reload
  
 

安全组

1.买的阿里云机器803306,8000 端口开放的
2.但是,3306,6379 8000端口可能没打开
3.不打开安全组的端口,是访问不进来的