(1) proxy

前端的端口在:localhost:3000
后端的端口在:localhost:1234
所以要在webpack中配置proxy选项 (proxy是代理的意思)

在package.json中添加如下配置-------这里用的是create-react-app脚手架eject后的项目
"proxy":"http://localhost:1234" // 把前端的请求都代理到1234端口,和后端一致,即可访问后端接口

(2) axios

配置好proxy后,就可以用axios跨域了

在组件中
import React,{Component} from 'react';
import { Redirect } from 'react-router-dom';
import axios from 'axios'; // 引入axios
export default class Login extends Component {
     goLog = () => {
    this.props.goLogin();
 }
    goGetData = () => {
         axios.get('/data') // 使用axios
      .then(res => {
        console.log(res,'res')
      } ) }
  render() {
  return (
    <div> 登陆页面 { this.props.login && this.props.login.isLogin ? <Redirect to="/user" /> : null }
      <div onClick={this.goLog}> 点击登陆 </div>
      <div onClick={this.goGetData}> 点击---用axios获取后端数据 </div>
    </div> )
} }

(3)axios拦截器

作用:当一个请求发出的时候,会先流过 interceptors 的 request 部分,接着请求会发出,当接受到响应时,会先流过 interceptors 的 response 部分,最后返回

  • interceptor是拦截器的意思
  • 作用:在请求或响应被 then 或 catch 处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}); // 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
}); 如果你想在稍后移除拦截器,可以这样:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor); 可以为自定义 axios 实例添加拦截器
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

 

  • 实例:如下

    (1) config.js文件
    
    import axios from 'axios';
    
    import {Toast} from 'antd-mobile';         // antd-mobile轻提示组件Toast
    
    // 拦截请求
    axios.interceptors.request.use(config => {
    Toast.loading('加载中',1) // loading组件,显示文字加载中,自动关闭延时1s
    console.log('request go');
    return config;
    }, err => {
    console.log('请求失败')
    return Promise.reject(err)
    }) //拦截响应
    axios.interceptors.response.use(config => {
    Toast.hide() // 销毁Toast组件
    console.log('response get')
    return config;
    }, err => {
    console.log('响应失败')
    return Promise.reject(err)
    }) -------------------------------------------------------------
    (2) 在入口文件index.js文件中引入上面的cofig.js文件 import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import registerServiceWorker from './registerServiceWorker';
    import {Provider} from 'react-redux';
    import {store} from './store/store.js';
    // import UserContainer from './component/user/container.js';
    import './config/config.js'; import {BrowserRouter} from 'react-router-dom' ReactDOM.render(
    <Provider store={store}>
    <BrowserRouter>
    <App></App>
    </BrowserRouter>
    </Provider>
    , document.getElementById('root'));
    registerServiceWorker();

(4) css Modules模块化方案

  • 支持less和sass的语法
  • 解决命名冲突污染等问题
  • 使用JS和CSS分离的写法,不会改变大家的书写习惯
  • 解决依赖管理不彻底,无法共享变量,代码压缩不彻底
    使用webpack项目中,只需要简单的配置,如下:
webpack.config.dev.js

注意:这里需要提前安装css-loader插件!!

{
module: {
rules:[
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader?modules', // 在css-loader后添加 ?modules即可
// loader: 'css-loader?modules&localIdentName=[name]-[hash:base64:5]'
// modules后面还可以跟具体的命名规则
// localIdentName 是设置生成样式的命名规则。
}
] }
]
}
}
------------------------------------------------------------------------------
换一中写法:(一样的) {
test: /\.css$/,
exclude: /node_modules\/antd/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1, // 在css-loader前应用的loader的数目, 默认为0
modules:true, // 开启css-modules模式, 默认值为flase
localIdentName:'[name]-[local]-[hash:base64:8]',//css-modules模式下local类名的命名
},
},
]
},

(5) Ant Design Mobile (antd-mobile)

  • 按需加载
    除了安装 ( antd-mobile ) 之外,还需要安装 ( babel-plugin-import )
  • 这里有个坑:在package.json中配置babel的时候(babel-plugin-import插件在安装后,需要配置babel ),配置完,引入ant组件使用,样式会失效!!!而在未使用css-modules模块化方案的时候,ant-mobile能正常使用,( 要使用css-modules的话,要在webpack.config.json中做如下配置:(!)
    (踩坑与填坑) https://segmentfault.com/q/1010000011965218
(!)

 {
test: /\.css$/,
include: /node_modules\/antd/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
modules:false
},
},
]
},
{
test: /\.css$/,
exclude: /node_modules\/antd/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
modules:true,
localIdentName:'[name]-[local]-[hash:base64:8]',
},
},
]
},
安装:
cnpm install antd-mobile --save 使用:
import { Button } from 'antd-mobile';
import 'antd-mobile/dist/antd-mobile.css'; 按需加载:
(1)安装babel按需加载插件 babel-plugin-import cnpm install babel-plugin-import --save-dev (2)在create-react-app脚手架eject后,package.json文件中,配置如下:
// 自己搭建可以写在.babelrc中
"babel": {
"presets": [
"react-app"
],
"plugins": [
"transform-decorators-legacy",
["import", { "libraryName": "antd-mobile", "style": "css" }]
]
} (3) 使用
import { Button } from 'antd-mobile';
...
... (4) 因为使用了css-modules模块化方案,所以在配置packageg.json中babel的时候,要修改成如下配置: {
test: /\.css$/,
include: /node_modules\/antd/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
modules:false
},
},
]
},
{
test: /\.css$/,
exclude: /node_modules\/antd/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
modules:true,
localIdentName:'[name]-[local]-[hash:base64:8]',
},
},
]
},

(6) css-loader 和 ( style-loader, postcss-loader )

  • css-loader: 在js中加载css
  • style-loader: 把加载的css作为style标签内容插入到html中
  • postcss-loader:
    如果某些css要考虑到浏览器的兼容性(比如css3中的flex),我们要webpack在打包的过程中自动为这些css属性加上浏览器前缀,这时就用到了postcss-loader和它对应的插件autoprefixer。
    http://blog.csdn.net/szu_aker/article/details/72588857

(7) 非路由组件如何使用this.props.history

如果是路由组件,访问history一般都是通过this.props.history来操作history

  • 而非路由组件通过 {withRouter} 来使用this.props.history
import React from "react";
import {withRouter} from "react-router-dom"; // 引入withRouter class MyComponent extends React.Component {
...
myFunction() {
this.props.history.push("/some/Path");
}
...
}
export default withRouter(MyComponent); // 用withRouter包裹该class ---------------------------------------------------------------------------- this.props.location.pathname 获取当前的url

(8) body-parser中间件

可以通过body-parser对象创建中间件,当接受到客户端请求时所有的中间件都会给req.body添加属性,请求内容为空时,解析为空或者错误。

  • body-parser是非常常用的一个express中间件,作用是对post请求的请求体 ( req ) 进行解析。
server.js

const express = require('express');
const bodyParser = require('body-parser'); // 引入body-parser
const cookieParser = require('cookie-parser'); // 引入cookie-parser const app = express();
const user = require('./user.js'); app.use(bodyParser.json()) // 使用body-parser
app.use(cookieParser()) // 使用cookie-parser app.use('/one', user)
app.get('/', function(req, res){
res.send('<p>后端页面</p>')
}) app.listen(3333, function() {
console.log('express port 1212 is going')
}) ----------------------------------------------------
(存入cookie) user.js Router.post('/login', function(req,res){
const {user, password} = req.body; // req.body是body-parser解析的请求体
console.log(req.body, 'req.body')
User.findOne({user,password: MD5PASSWORD(password)}, function(err,doc){
if(!doc){
return res.json({
code:1,
msg: '用户名或密码错误'
})
}
res.cookie('userId', doc._id) // cookie-parser的使用--------写入cookie
// login接口存入一个cookie,name是userId,value是res._id // 存cookie是在res中
// 取cookie是在req中
return res.json({
code:0,
data: doc
})
})
}) ----------------------------------------------------
(取出cookie) Router.get('/info',function(req,res){
// 用户有没有cookie
const {userId} = req.cookies; // 取出cookie,中的userId-------取出cookie,注意是复数!!!! if(!userId) {
return res.json({
code:1
})
} User.findOne({_id: userId}, function(err,doc){
if(err) {
return res.json({
code:1,
msg: '后端出错'
})
}
return res.json({
code:0,
data: doc
})
}) })

(9) cookie-parser中间件

cookies最常用在‘记住密码’和‘自动登录’。
cookies 存在于客户端,安全性较低,一般要存入加密后的信息,并且大部分情况下需要设置过期时间或不使用删除。

  • cookie类似于一张身份卡,登陆后,由服务端返回,带着cookie即可访问受限资源

  • 存cookie

res.cookie('userId', doc._id)     // name是userId,value是doc._id
  • 取cookie-------------注意:是复数 req.cookies

    const {userId} = req.cookies
    // const userId = req.cookies.userId

(10) utility

md5加密库

安装:
cnpm install utility --save 引入和使用:
const utility = require('utility'); Router.post('/register', function(req,res){ console.log(req.body,'req.body'); const {user, password, type} = req.body;
User.findOne({'user':user},function(err,doc){
if(doc){
return res.json({
code:1,
msg: '用户名存在'
})
}
User.create({
'user': user,
'password':utility.md5(password), // 使用--------------
'type':type
},function(err,doc){
if(err){
return res.json({
code:1,
msg:'后端出错了'
})
}
console.log('用户名不存在,已添加到数据库')
return res.json({
code:0
})
})
})
}) ---------------------------------------------------- 后端比较合格的加密函数: function MD5PASSWORD(password) {
const salt = 'more_complex_passWord187873871~@!@@@##$$%%DAxiao';
return utility.md5( utility.md5(password + salt) );
}

(11) nodemon

原始node中的express框架,每次修改js代码后,都要重新手动启动才能看到改动后的效果,调试起来十分不方便。所以我引入了nodemon模块了弥补这样缺点。

  • 全局安装
 cnpm install nodemon -g
  • 修改配置


在package中配置的script中配置的代码 :

“node”: "node server/server.js"

------
修改为 "node": "nodemon server/server.js"

(13) 登陆跳转的逻辑

(1) 注册时拿到注册的所有信息,把信息传到redux中,先做前端判断(用户名和密码是否为空,密码输入是否一致 等),然后在redux的action请求后端user/login接口,传入注册信息到请求体中,规定如果后端返回res.status===200&&res.data.code=0就表示注册成功,把注册信息写入redux的reduce中,否则表示注册失败,并且由后端返回错误信息,并且存入redux,然后取出显示在前端页面 。 ----后端注册接口的逻辑:拿到前端传过来的请求数据,然后查找数据库时候存在,如果存在,表示已经注册,返回code===1,和msg=已经注册过了。否则表示未注册,则把前段数据存入数据库。并返回code表示注册成功
(2) 注册后的跳转逻辑:根据注册时的身份(genius或者boss) 和 (是否有头像) 决定跳转到 boss页面,genius页面, bossinfo页面,geniusinfo页面

(3) 登陆时,拿到登陆的所有信息,然后做前端判断(用户名,密码是否为空),然后请求后端user/login接口,传入如果返回 res.status===200 && res.data.code ===0表示登陆成功,然后拿到后端返回的数据,存入redux的reducer中。否则表示登陆失败,吧后端返回的错误信息,存入redux,返回给前端页面。--------后端接口:拿到前段给到的请求体,然后查找数据库,如果doc不存在,就返回res.jsoln({code:1}),否则表示用户信息在数据库中存在,这是存入cookie,res.cookie('名字',doc._id),然后返回数据库中存在的用户信息,返回给前段接口使用
(4) 登陆后的跳转逻辑:和注册时候一样
(5) 如果是其他页面,不在login,和register两个页面中,则在前段请求另一个接口,ingo接口,,如果后端返回code是0,res.status是200,表示有用户信息,则拿到后端返回的数据存入redux, 否则表示没有用户信息,路由跳转到登陆页面。-------后端接口逻辑:首先在该接口验证cookie是否存在,cost {usrId} = req.cookies,如果不存在返回res.json({code:1}), 然后查找数据库,有数据返回数据,没有返回相应的状态码

(14) mongoose添加的两种方式

(1) create方式
缺点: 不能存储id User.create({
user,
password: MD5PASSWORD(password),
type
}, function(err,doc){
if(err) {
return res.json({
code:1,
msg: '后端出错'
})
}
return res.json({
code:0
})
}) -------------------------------------------- (2) new mongoose.model().save方式: Router.post('/register', function(req,res) {
console.log(req.body)
const { user, password, type } = req.body; User.findOne({user}, function(err,doc){
if(doc) {
return res.json({
code: 1,
msg: '已经注册过了'
})
}
const userModel = new User({ // new mongoose.model('user')
user,
password: MD5PASSWORD(password),
type
})
userModel.save(function(err,doc){ // .save
if(err){
return res.json({
code:1,
msg:'后端出错'
})
}
const {user, type, _id} = doc
res.cookie('userId', _id) // 在注册页面存cookie
return res.json({
code:0,
data:doc
}) }) }) })

Entity结构 http://blog.csdn.net/sinat_25127047/article/details/50560167

(15) mongoose相关语法

  • findByIdAndUpdate

Router.post('/update', function(req,res) {
const {userId} = req.cookies;
console.log(req.cookies,'req.cookies');
if(!userId) {
return json.dumps({
code:1
})
}
const body = req.body
// findByIdAndUpdate(需要查找的id,需要更新的数据,回掉)
User.findByIdAndUpdate(userId,body,function(err, doc){ ---------------------
const data = Object.assign({},{
user: doc.user,
type: doc.type
},body); // 把body对象 和user type 合并赋值给data------body是前端请求的实时更新的请求体
return res.json({
code:0,
data
})
})
})

(16) Array.find()

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

  • 找出第一个符合条件的数组成员,返回该成员
  • 参数是回调函数fallback(value,index,array)
  • 没有找到符合的成员,返回undefined
  • 还可以接受除fallback回调函数之外的,第二个参数,用来绑定回调函数的this对象。

[1, 4, -5, 10].find(n => n < 0) // -5 --------------------------------------------------- [1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10 find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。 --------------------------------------------------- function f(v){
return v > this.age;
}
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person); // 26

(17) Array.findIndex()

数组实例的findIndex方法返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

  • 找出第一个符合条件的数组成员,返回该成员的位置
  • 参数是回调函数fallback(value,index,array)
  • 没有找到符合数组成员的位置,返回-1
  • 还可以接受除fallback回调函数之外的,第二个参数,用来绑定回调函数的this对象。

[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2

(18) nodeJS 取参

  • req.body ----------是post请求,获取参数
  • req.query----------是get 请求,获取参数
  • req.params
  • req.param()

(19) browser-cookies

git地址:https://github.com/voltace/browser-cookies
安装:cnpm isntall browser-cookies -S

  • cookies.set 设置cookie
  • cookies.get 获取cookie
  • cookies.erase 清除cookie ------------- erase是清除,抹去的意思
var cookies = require('browser-cookies');

cookies.set('firstName', 'Lisa');
cookies.set('firstName', 'Lisa', {expires: 365}); // Expires after 1 year
cookies.set('firstName', 'Lisa', {secure: true, domain: 'www.example.org'}); cookies.get('firstName'); // Returns cookie value (or null) cookies.erase('firstName'); // Removes cookie

(20) window.location.href = window.location.href强制刷新页面

http://blog.csdn.net/github_37483541/article/details/59481084


注销登陆: logout =() => {
// erase是清除,抹掉的意思
// browserCookies.erase('userId');
// window.location.href = window.location.href
const alert = Modal.alert
alert('注销','确定要注销登陆吗?',[
{text:'取消', onPress: () => console.log('canscel')},
{text:'确定', onPress: () => {
browserCookies.erase('userId');
// window.location.href = window.location.href
this.props.logoutAll(); // 该方法清除redux中register存着的数据
}}
])
}

============

来源于https://www.jianshu.com/p/1a6e31a7e923
 

12. 前后端联调 + ( proxy代理 ) + ( axios拦截器 ) + ( css Modules模块化方案 ) + ( css-loader ) + ( 非路由组件如何使用history ) + ( bodyParser,cookieParser中间件 ) + ( utility MD5加密库 ) + ( nodemon自动重启node ) + +的更多相关文章

  1. [django]django配合前端vue前后端联调,django服务端解决跨域(django-cors-headers)

    django内部csrf post提交数据解决 https://www.cnblogs.com/iiiiiher/articles/9164940.html 前端写了个页面,里面$.post发现403 ...

  2. 研发流程 接口定义&开发&前后端联调 线上日志观察 模型变动

    阿里等大厂的研发流程,进去前先了解一下_我们一起进大厂 - SegmentFault 思否 https://segmentfault.com/a/1190000021831640 接口定义 测试用例评 ...

  3. 【转载】由浅入深分析mybatis通过动态代理实现拦截器(插件)的原理

    转自:http://zhangbo-peipei-163-com.iteye.com/blog/2033832?utm_source=tuicool&utm_medium=referral 我 ...

  4. Vue2学习小记-给Vue2路由导航钩子和axios拦截器做个封装

    1.写在前面 最近在学习Vue2,遇到有些页面请求数据需要用户登录权限.服务器响应不符预期的问题,但是总不能每个页面都做单独处理吧,于是想到axios提供了拦截器这个好东西,再于是就出现了本文. 2. ...

  5. axios拦截器搭配token使用

    在了解到cookie.session.token的作用后学习token的使用 cookie是随着url将参数发送到后台,安全性最低,并且大小受限,不超过4kb左右,它的数据保存在客户端 session ...

  6. vue导航守卫和axios拦截器的区别

    在Vue项目中,有两种用户登录状态判断并处理的情况,分别为:导航守卫和axios拦截器. 一.什么是导航守卫? vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航.(在路由跳转时 ...

  7. vue axios拦截器 + 自编写插件 实现全局 loading 效果;

    项目需求:用自定义的 .gif 图标实现全局 loading 效果:为避免在每个页面手动添加,且简单高效的实现,经查阅资料,最终采用了 vue axios拦截器 + 自编写 loading 插件:下面 ...

  8. Vue基于vuex、axios拦截器实现loading效果及axios的安装配置

    准备 利用vue-cli脚手架创建项目 进入项目安装vuex.axios(npm install vuex,npm install axios) axios配置 项目中安装axios模块(npm in ...

  9. axios拦截器的使用方法

    很多时候我们需要在发送请求和响应数据的时候做一些页面处理,比如在请求服务器之前先判断以下用户是登录(通过token判断),或者设置请求头header,或者在请求到数据之前页面显示loading等等,还 ...

随机推荐

  1. eclipse-JEE配置Tomcat并发布第一个项目

    一.配置过程 Window--preferences--Server--Runtime Environment, 然后点击add 我下载的是Tomcat7.0,选择你的版本就行了 选择Tomcat的安 ...

  2. SpringBoot项目中应用Jedis和一些常见配置

    优雅的使用Jedis Redis的Java客户端有很多,Jedis是其中使用比较广泛和性能比较稳定的一个.并且其API和RedisAPI命名风格类似,推荐大家使用 在项目中引入Jedis 可以通过Ma ...

  3. MySQL5.7 import表结构报错超出表空间界限

    事后测试了一下,一下方法就是垃圾,看看可以,别跟着学!!! 数据库重启后,问题依然暴露出来了,参数什么的都是扯,擦 记录一个困扰我好几天的问题.先贴上报错: space name jxtms/Cost ...

  4. Java实现tif/tiff/bmp图片转换png图片

    package org.analysisitem20181016.test; import java.io.File; import java.io.FileOutputStream; import ...

  5. Codeforces Round #565 (Div. 3)--D. Recover it!--思维+欧拉筛

    D. Recover it! Authors guessed an array aa consisting of nn integers; each integer is not less than ...

  6. C#通用类库整理--字符串处理类

    在程序开发中通常需要将字符串转为自己想要的结果,以下三个类库主要实现: 1.GetStrArray(string str, char speater, bool toLower)  把字符串按照分隔符 ...

  7. 1068 Find More Coins (30分)(dp)

    Eva loves to collect coins from all over the universe, including some other planets like Mars. One d ...

  8. LeetCode | 169. 多数元素

    给定一个大小为 n 的数组,找到其中的多数元素.多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是非空的,并且给定的数组总是存在多数元素. 示例 1: 输入: [3,2,3] ...

  9. 微信小程序实现滑动tab切换和点击tab切换并显示相应的数据(附源代码)

    这里主要用到了swiper组件和三目运算,直接上代码, 样式只有三个class,简单粗暴,懒的小伙伴们可以直接拿来用,喜欢的点个支持 <view> <view class=" ...

  10. IntelliJ IDEA 在方法大括号中{}点击回车多出一个},如何取消

    在 File - settings - Editor - General- Smart Keys - Enter 去掉 Insert pair '}' 的对勾就可以了