前端的端口在:localhost:3000
後端的端口在:localhost:1234
因此要在webpack中配置proxy選項 (proxy是代理的意思)javascript
在package.json中添加以下配置-------這裏用的是create-react-app腳手架eject後的項目 "proxy":"http://localhost:1234" // 把前端的請求都代理到1234端口,和後端一致,便可訪問後端接口
配置好proxy後,就能夠用axios跨域了php
import React,{Component} from 'react';import { Redirect } from 'react-router-dom';import axios from 'axios'; // 引入axiosexport 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> )} }
做用:當一個請求發出的時候,會先流過 interceptors 的 request 部分,接着請求會發出,當接受到響應時,會先流過 interceptors 的 response 部分,最後返回css
// 添加請求攔截器 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();
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類名的命名 }, }, ] },
(!) { 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]', }, }, ] },
若是是路由組件,訪問history通常都是經過this.props.history來操做historyhtml
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
能夠經過body-parser對象建立中間件,當接受到客戶端請求時全部的中間件都會給req.body添加屬性,請求內容爲空時,解析爲空或者錯誤。前端
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 }) }) })
cookies最經常使用在‘記住密碼’和‘自動登陸’。
cookies 存在於客戶端,安全性較低,通常要存入加密後的信息,而且大部分狀況下須要設置過時時間或不使用刪除。java
cookie相似於一張身份卡,登錄後,由服務端返回,帶着cookie便可訪問受限資源node
res.cookie('userId', doc._id) // name是userId,value是doc._id
const {userId} = req.cookies // const userId = req.cookies.userId
md5加密庫react
安裝:
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) ); }
原始node中的express框架,每次修改js代碼後,都要從新手動啓動才能看到改動後的效果,調試起來十分不方便。因此我引入了nodemon模塊了彌補這樣缺點。webpack
cnpm install nodemon -g
在package中配置的script中配置的代碼 : 「node」: "node server/server.js" ------ 修改成 "node": "nodemon server/server.js"
(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頁面ios(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}), 而後查找數據庫,有數據返回數據,沒有返回相應的狀態碼
(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
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 }) }) })
數組實例的find方法,用於找出第一個符合條件的數組成員。它的參數是一個回調函數,全部數組成員依次執行該回調函數,直到找出第一個返回值爲true的成員,而後返回該成員。若是沒有符合條件的成員,則返回undefined。
[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
數組實例的findIndex方法返回第一個符合條件的數組成員的位置,若是全部成員都不符合條件,則返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) // 2
git地址:https://github.com/voltace/browser-cookies
安裝:cnpm isntall browser-cookies -S
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
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存着的數據 }} ]) }