commonJs && es6
commonjs
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
每个模块内部,module
变量代表当前模块。这个变量是一个对象,它的exports
属性(即module.exports
)是对外的接口。加载某个模块,其实是加载该模块的module.exports
属性。
require
方法用于加载模块
以上来自CommonJS规范-阮一峰
commonjs的详细:可以从node的使用中获悉
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
每个模块内部,module
变量代表当前模块。这个变量是一个对象,它的exports
属性(即module.exports
)是对外的接口。加载某个模块,其实是加载该模块的module.exports
属性。
require
方法用于加载模块
以上来自CommonJS规范-阮一峰
commonjs的详细:可以从node的使用中获悉
注:有缺陷,没有进行scroll事件的防抖、节流处理
某项目需要一下抖音的下拉刷新效果,目前做出来的效果如下:
做的还是很勉强,简而言之:
spinner
spinner
要能跟着旋转spinner
需要能跟着倒着旋转回去,在超过一定距离后,即成功取消刷新,spinner
消失spinner
开始无限旋转,直到页面刷新完成也就是一个带缺口的1/4圆怎么做?
也即:设一个宽高相等的div
,再设 border-radius: 50%;
,这样就把div变成了一个圆
再设border: 4px solid transparent;
,这样就形成了一个圆环,但是这个圆环还是透明的,还看不出效果
1/4圆环的最重要一步就来了:
border-top-color: #f5f5f5;
border-left-color: #f5f5f5;
border-bottom-color: #f5f5f5;
大家可以看出这个缺口是哪一边吗? --对的,就是右边,不过还隐藏了一点就是div默认的background
的就是background: transparent;
,所以此时显示的圆环就是一个4px
宽的背景色为#f5f5f5
的1/4圆环
一个属性搞定:transform: rotate(360deg);
,此时表示将元素旋转360度
ransform 属性向元素应用 2D 或 3D 转换。该属性允许我们对元素进行旋转、缩放、移动或倾斜
也是这次的核心:
主要思路: touchstart
事件得到用户滑动的开始坐标,touchmove
中去判断用户滑动的的位移,touchend
事件判断用户滑动结束时的坐标,有了这3对值,就可以进行很多操作了
touchstart
: 得到startX
、startY
touchmove
: 得到moveX
、moveY
touchend
: 得到endX
、endY
要手指下滑,spinner
跟着旋转,也就是要手指下滑的距离与spinner
的transform: rotate(xxxdeg);
成比例关系,手指下滑的距离就是moveY-startY
可以用diff
表示
// 使得转动的角度,随着diff的距离变动
spinner.style.transform = 'rotate('+diff*1.2+'deg)';
这样基本的思路就确定了,但还有一个隐藏的地方,怎么确定用户是在下滑?
参考:模仿抖音的全屏滚动效果
GetSlideAngle(dx, dy) {
// atan2() 方法可返回从 x 轴到点 (x,y) 之间的角度
return Math.atan2(dy, dx) * 180 / Math.PI;
},
GetSlideDirection(startX, startY, endX, endY) {
let dy = startY - endY;
let dx = endX - startX;
let result = 0;
if (Math.abs(dx) < 50 && Math.abs(dy) < 50) {
return result;
}
let angle = this.GetSlideAngle(dx, dy);
if (angle >= -45 && angle < 45) {
result = 4;
} else if (angle >= 45 && angle < 135) {
result = 1; //向上
} else if (angle >= -135 && angle < -45) {
result = 2; // 向下
} else if (
(angle >= 135 && angle <= 180) ||
(angle >= -180 && angle < -135)
) {
result = 3;
}
return result;
}
之后在touchmove
的时候将,startX
、startY
、moveX
、moveY
传入就可以判断此时是否在下滑
上述的spinner
与滑动距离的随动关系,仍可以用,主要是怎么判断用户是在取消刷新?
例如,用户下滑到一定程度,再上滑,但上滑不超过起始点,那么如果一开始用的是startX
和startY
来判断,此时用户仍会被判断会下滑啊...
解决方法:定义一个maxDown
变量来存储用户下滑的最大距离,下滑过程中,touchmove
事件会被不断的触发,于是diff
的值就会不断被计算出来
// 存储用户下滑的最大距离
if(this.maxDown<diff) {this.maxDown = diff}
// 但用户上滑到一定距离的时候
if(this.maxDown-diff) > this.maxDown*2/3) {
// 下滑标志置为false
this.moveDownFlag = false;
// 隐藏spinner
this.spinner = false;
}
此时用户触发刷新操作,spinner
开始无限旋转,直到页面刷新完成
这里判断用户正常下滑比较容易,只要在touchend
事件时,用户是在下滑而且之前的moveDownFlag
是为true
,这样就可以了
但怎么让spinner无限旋转,而且要充当页面刷新的loading效果呢?
我采用的是vue
,所以可以用动态class
来实现
vue
的template
部分:
<div class="main__indicator" ref="spinner" :class="{'active': isLoading}" v-show="spinner"></div>
为了性能,这里采用css动画
,使用animation
+keyframes
的组合,CSS @keyframes Rule
sass
:
@keyframes kebab-spinner-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
&.active {
animation:kebab-spinner-rotate 0.8s infinite linear;
}
js:
if(direction === 2 && this.moveDownFlag) {
this.isLoading = true;
// 发送ajax更新,此时充当loading效果
// ajax code ...
if(response.data.code === 200) {
this.isLoading = false;
}
}
但有一个缺陷就是,当spinner
无限旋转时与之前的旋转角度有点衔接补上。。。
需要注意的是,spinner
是固定定位的,而从一开始的预览图中可以看出,它是水平居中的,怎么实现固定定位的水平居中呢?
我的方法是参考的网上的,具体出处有点不清楚了...
left: 50%;
height: 30px;
width: 30px;
margin-left: -15px;
借用同学腾讯云的服务器,因为webview
需要开启摄像头的缘故,只能运行在有https
的环境下,于是开启了http
转https
一开始因为是腾讯云,有官方的上https的解决办法,但是尴尬的是同学说在把证书配置负载均衡的那一步,就找不到实例...,应该是我们就没开启任何的nginx
,apache
的服务器之类的吧,于是索性就直接用https://letsencrypt.org,
参考资料:
ubuntu使用Let’s Encrypt设置https,最终是用的这个,但是要注意选择http跳转方式(2),而且注意的是网址一定不要输错
由于自己一开始没有选择http跳转方式(2)(怕影响到已存在的服务...此处需谨慎),因为怕在服务器上已经运行的tomcat
的8080
会被屏蔽掉,但是却发现首页也没有加上https
后来在如何免费的让你的网站变得更加安全 - HTTPS,这篇文章中找到灵感,sudo certbot --nginx
,再输一下这个命令不就有了吗? 后来才发现自己不仅一开始没选好,就连网址都输错了...
这个才是自己的痛苦之源,因为对nginx
一点都不熟,简直崩盘...
阿里云配置 node.js + Nginx 反向代理,写nginx
配置文件的时候参考的这个,但没有成功...,对nginx不熟啊...
How To Set Up a Node.js Application for Production on Ubuntu 16.04,stackoverflow上推荐的
Deploying NodeJS using Express with NginX and Let's Encrypt,比较详细,也一边参考了这个
[[新手]nginx反向代理负载均衡配置](https://segmentfault.com/a/1190000003824014)
CentOS 7 yum 安装 Nginx,另外另一个同学有cenos7
的服务器,也试了试nginx
,发现与ubuntu
还是有一些不同,
403
nginx默认配置的静态资源目录(root
),直接换成dist
目录(直接用xftp上传报错,没权限。用cp -r /home/uftp/xixigiggling/. /var/www/html
解决),就可以变成直接运行单页面应用了(佩服自己的机智),但是打开首页却报错,403 forbidden
,查nginx日志
# 万一起不来 日志日志日志,重要的事情说三遍!!!
tail -f /var/log/nginx/error.log
可以发现是 Permission denied
的权限错误,于是设置linux文件的权限,dist的文件有index.html
和static
,chmod 777 index.html
,但是注意在文件夹开启权限要用-R:chmod 777 -R static
参考资源:
nginx静态资源文件无法访问,403 forbidden错误
不熟悉nginx
!!!
遇到一个跨域问题,说到这里大家就心里默然一笑了,因为不外乎就那样的balabala,但这次有点不一样的在于:后端确定自己已经开启了跨域!这...就有点尴尬了
首先是最简单的http://10.63.231.79:8080
向http://47.106.111.100:8088
发post请求,无疑已经跨域了,
其次,因为我的是vue-cli
搭建的(我负责webview
部分),然后用的axios
发请求,按api地址来发数据的时候,报错403
,如下图:
看起来,我很有道理,但是有两个问题
第一,为什么postman
可以成功呢?
第二,为什么安卓端的请求也可以成功呢?
安卓端的请求如下:
通过为什么使用postman发送请求时不会有跨域问题?得知,
准确的跨域定义:当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求,通俗一点,正常的跨域情况,是你访问了一个A网站,然后这个网站返回的资源里面,请求了B网站/端口的资源,于是就跨域了
跨域这个情况只会出现在浏览器页面里,因为实际上是浏览器由于安全原因限制了这些请求的访问。在postman里面,实际上每发出一个请求,都是在独立请求一个资源
还有很解惑的一句话:
应该是POSTMAN中有个类似java程序或者node 代理了跨域接口,先用node去请求跨域接口,得到数据,然后本地发起ajax请求,实际请求的是node代理过后的接口,就不存在跨域了
只有在浏览器端发 ajax 请求才会存在跨域
http请求不会存在跨域
先不说正确性,其中的那句,实际请求的是node代理过后的接口,立马联想到,这应该也是设置代理能解决跨域的原因吧(将ajax请求交给代理变成由代理发出http请求),也就是句子最后的,只有在浏览器端发ajax请求才会存在跨域,http请求不会存在跨域
的确不明白,但似乎也是这样的理由吧?
后询问安卓的同学是使用的okhttp
,上面赫然写着这样一句话:
OkHttp is an HTTP client
这不就差不多又是一个postman
吗...似乎到这里事情已经很明白了,但我们需要再看一下的是
Response to preflight request doesn't pass access control check: No'Access-Control-Allow-Origin'
header is present on the requested resource. Origin'http://10.63.231.79:8080'
is therefore not allowed access. The response had HTTP status code 403.
preflight request
?参考链接: HTTP访问控制(CORS)-MDN
规范要求,对那些可能对服务器数据产生副作用的
HTTP
请求方法(特别是GET 以外的 HTTP请求,或者搭配某些MIME
类型的POST
请求),浏览器必须首先使用OPTIONS
方法发起一个预检请求(preflight request
),从而获知服务端是否允许该跨域请求"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
另联想到,遇到的axios跨域(也就是上述的报错),搜索到的axios可以解决跨域访问的问题吗?,说道:
当server
端不支持跨域,如果不是自己开发的,那么可以自己写个后端转发该请求,用代理的方式实现。(后来的自己就是这样解决跨域的)
当server
端支持跨域,但不能响应OPTIONS
请求时,如果 server
端也支持简单请求(见下方定义),特别是 axios POST
请求时,默认使用 JSON
格式,改成 string
问题就解决了!Using application/x-www-form-urlencoded format,需要转成application/x-www-form-urlencoded
,可以用qs.stringify(data)
,那么这里又是为什么可以呢?
重点就在于简单请求,查看上述MDN的介绍:
某些请求不会触发
CORS
预检请求。本文称这样的请求为“简单请求”若请求满足所有下述条件,则该请求可视为“简单请求”:
其中条件有(还有其他,请看文档):
Content-Type
的值仅限于下列三者之一:text/plain
,multipart/form-data
,application/x-www-form-urlencoded
原来这个原理就是,把跨域的请求,通过转换成简单请求,这样就不会触发了OPTIONS
了,但我的确这样做了之后,发送的预检请求报200了,但是结果控制台还是报跨域的错...这?
注意:这些跨域请求与浏览器发出的其他跨域请求并无二致。如果服务器未返回正确的响应首部,则请求方不会收到任何数据。因此,那些不允许跨域请求的网站无需为这一新的 HTTP 访问控制特性担心。
额...原来白高兴一场...
后续再看MDN文档时更找到一个有力的证据判断服务器是否开跨域:
假如站点 http://foo.example
的网页应用想要访问 http://bar.other
的资源,请求报文和响应报文:
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
请求首部字段 Origin
表明该请求来源于 http://foo.exmaple
,响应中携带了响应首部字段 Access-Control-Allow-Origin
。使用Origin
和 Access-Control-Allow-Origin
就能完成最简单的访问控制
Access-Control-Allow-Origin: *
表明,该资源可以被任意外域访问
Access-Control-Allow-Origin: http://foo.example
表明,仅允许来自 http://foo.example
的访问
这就指明了一个更强的方法判断服务器开没开跨域:在响应中,查看是否有Access-Control-Allow-Origin
字段
想到怎么测试呢? 用github
的api
啊:
可以看到github
的api
完全支持跨域
事至此,可以看到这个证明题基本已经差不多了,那就是:服务器没开跨域!
首先一开始由于不确定是不是跨域的问题,因此换了三种发ajax请求的框架,axios
,vue-resource
(重识vue-resource ),jquery
,但结果其实都会报错,
其中用jquery
发post
请求到后端的时候,用jsonp
来发post
请求,来解决跨域:
$.ajax('http://47.106.111.100:8088/rest/app/register', {
type: "POST",
data: test,
dataType: 'jsonp',
crossDomain: true,
success: function (data) {
alert('hello');
if (data && data.resultcode == '200') {
console.log(data.result.today);
}
}
});
还是会出现Cross-Origin Read Blocking (CORB) blocked cross-origin response
那么这是为什么呢?
首先定义jsonp
: 创建一个 script
标签,将 src
设置为目标请求,插入到 dom
中,服务器接受该请求并返回数据,数据通常被包裹在 回调钩子
中
可以用
jsonp
发送post
请求么?显然不行,看过支持 post 请求的 script 么?
详细解释:
Response to preflight request doesn't pass access control check
总结:
也就是jsonp:
post
请求跨域的解决有:
If you do NOT want to:
或者
You are running into CORS issues.There are several ways to fix this.
于是凉凉...,post
请求肯定触发跨域,而jsonp
是不行了,联想到之前有过印象,webpack
可设置代理来解决跨域问题(大概是上面postman提到的那种思想),于是查一下,get!
webpack 前后端分离开发接口调试解决方案,proxyTable解决方案
在config/index.js
里面找到proxyTable
proxyTable: {
"/rest": "http://47.106.111.100:8088"
},
这样的话,请求到 /rest/app/register
,现在会被代理到请求 http://47.106.111.100:8088/rest/app/register
。 更多的用法查看上面的http-proxy-middleware
文档即可
就是这样,all is done !
受同学所托,要爬一个网站
第一步很自然的,查看网页元素,看渲染的能不能直接抓下来,
但是用上request
,cherrio
,一查元素,为空?(页面上明明有),把request
的body
打印出来,才发现是ajax
,应对方法:打开chrome
,用Network
,终于查看到了请求,复制链接地址,竟然直接浏览器打开就可以获得到json
数据...
接下来就是漫长的数据整理工作了以及一直要弄明白的回调地狱的问题
以为返回的是json
,结果一直报错,才发现返回的内容是hxbase_json1({sum: 2660, list: [,…]})
,也就是真正的json内容在两个括号里面...
换言之,怎么获得两个指定的符号中间的内容?
第一反应:正则,但基本忘光了(以前就只是生搬硬套的用...),之后搜索中看到有人提到了直接用字符串的方法,str.substring(str.indexOf('('),str.indexOf(')'))
,这方法好是好,但是:
input: "hxbase_json1({XXXXxx(xxx)xxxx})"
output: ({XXXXxx(xxx
也就是如果中间有括号就不行(弃),如果要用字符串的方法的话,直接提取子串不就可以了!,str.slice(13, -1);
,主要发现其他请求都是返回的这个形式,所以直接写死也行,好的,第一关成功!
另,就在写总结的时候,发现找到了以前第一次爬网站的时候各种堆砌出来的较通用的正则匹配函数:
// 匹配前后缀,提取中间的内容
function getInnerString(source, prefix, postfix) {
if (prefix !== "<p>")
var regexp = new RegExp(encodeReg(prefix) + '.+' + encodeReg(postfix), 'gi');
else
var regexp = new RegExp(encodeReg(prefix) + '(?:(?!<\/p>)[\\s\\S])*' + encodeReg(postfix), 'gi');
var matches = String(source).match(regexp);
if (matches == null) {
let now = new Date();
matches = ['this is failed', now + ''];
}
var formatedMatches = matches.map(value => {
return value
.replace(prefix, '')
.replace(postfix, '');
});
return formatedMatches;
}
//转义影响正则的字符
function encodeReg(source) {
return String(source).replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1');
}
以为提取出字符串之间的内容就可以了
// 提取中间内容
let str = body.slice(13, -1);
// 把字符串转化为json
let testJson = JSON.parse(str);
...
// 报错
SyntaxError: Unexpected token s in JSON at position 1
参考链接:字符串转换成JSON的三种方式,终于知道为什么,因为必须要遵守json规范,而字符串里面的属性并没有引号...
示例发现一个更神奇的现象,只有外面用单引号,而属性用双引号才可以
let jee = '{"sum":2660}'; // 正确:输出{ sum: 2660 }
let jee = "{'sum':2660}"; // SyntaxError: Unexpected token ' in JSON at position 1
console.log(JSON.parse(jee));
于是这里的解决方法只能用eval
了(第一次觉得eval这么亲切!),完美!
现在整个流程差不多写成这样:
// 部分为伪代码
for(let i= 11; i<=17 ;i++) {
// 先请求起始url,借此得到所有的页码数
let first = "xxx";
Request(first, (error, response, body)=> {
let str = body.slice(13, -1);
let testJson = eval("(" + str + ")");
let sum = testJson.sum;
// 获取到整个的页码
let pageNum = Math.floor(sum / 20);
for(let j=1; j<=pageNum; j++) {
let url = "xxx"+j;
Request(url, (error, response, body) => {
// 获取数据(伪代码)
list.push(data)
})
}
//写数据
fs.writeFile(i+"year.json", JSON.stringify(list),
function (err) {
if (err) throw err;
console.log('It\'s saved!');
}
);
})
}
这也就是传说中的回调金字塔(回调地狱),说说我自己遇到的情况,
第一,不一定每次请求都能正确无误,所以常常跑着跑着,突然报错了,然后这样的代码结构简直要命,实际中的我还在其中用了一个urls
数组先存下所有的url
再遍历发请求,也就是各种嵌套,各种异步,出错出在哪到找不到...,
第二,遇到了爬虫(或者异步中)很经典的问题,怎么判断回调结束了?这里的问题就是在fs.writeFile
的时候怎么确保list
已经获取到了所有的值?(11年有133条url,每条url指向20条数据)
第一种问题,以前有过一次爬博客园的经历,那里是采用Promise
化的方式解决的,request
库还有promise
的版本,promise
就保证了要么then
回调成功,要么err
/**
* 第一次爬博客园时的经历
* users 示例
{
raphael5200: {
username: 'raphael5200',
defaultPage: 'http://www.cnblogs.com/raphael5200/default.html?page=',
pages: 'http://www.cnblogs.com/raphael5200/default.html?page=2'
},
joyeecheung: {
username: 'joyeecheung',
defaultPage: 'http://www.cnblogs.com/joyeecheung/default.html?page=',
pages: 'http://www.cnblogs.com/joyeecheung/default.html?page=2'
}
...
}
*/
// 遍历每一个用户
for (let key in users) {
// 请求每一个用户的主页
rq(users[key].pages)
.then((body)=>{
let titles = [];
let reads = 0;
let replys = 0;
for (let i = 0; i < getPageNum(body); i++) {
// 请求用户发出来的每一个文章列表页
rq(users[key].defaultPage + '' + i)
.then((body) => {
// 提取当前文章列表页的所有文章标题,存到users[key].articles, 每篇文章的阅读数、评论数相加放置到readNum,replyNum中
// 写入 当时不知道怎么判断异步结束,直接用了一个比较hack的方法,不断的重写文件(最后能保存下来的就随缘了)
// fs.writeFile: Asynchronously writes data to a file, replacing the file if it already exists
fs.writeFile("users.json", JSON.stringify(users),
function (err) {
if (err) throw err;
console.log('It\'s saved!');
}
);
}).catch (function (err) {
//console.log(err);
});
}
})
.catch(function (err) {
console.log(err);
});
};
// 写入 还尝试过另一个方法,等待1分钟之后写入...(随缘)
setTimeout((users) => {
fs.writeFile("users.json",JSON.stringify(users),
function (err) {
if (err) throw err;
console.log('It\'s saved!');
}
);
}, 1000*1*60);
这次实际上是通过,把不必要的循环去掉,直接把10年17年要的数据,就分为8条url,在直接请求这8条(好在只有8条啊)
插播一条小细节: 之前的let str = body.slice(13, -1);
,常常报错,大致意思就是body
出问题了,undefined
或者什么的不能调用slice
方法,这样的话就又遇到了一个经典的问题:js怎么判断变量的类型?
参考链接:JavaScript学习总结(六)——JavaScript判断数据类型总结
// 外层加一个判断就避免了
if (typeof body === "string") {
let str = body.slice(13, -1);
第二种问题是采用的,settInterval
计数解决
参考链接:NodeJS的异步编程风格
例如:fs
去访问五个txt文件,1.txt
...5.TXT
const fs = require('fs');
const list = [];
for (let i = 1; i <= 5; i++ ) {
fs.readFile('./' + i + '.txt', 'utf-8' ,(err, data) => {
if (err) throw err;
list.push(data);
});
}
// 在后台不断的轮训,当list的长度达到指定值(也就是回调全部结束),此时就可以进行清除定时器
let intervalId = setInterval(() => {
console.log('waiting!...');
if(list.length === 5) {
console.log('SUCCESS');
// 注意setInterval与clearInterval的配合
clearInterval(intervalId);
}
}, 1000);
插话:有点疑惑的是,clearInterval(intervalId)
有种自身清除自身的感觉? 已知的,它们都是隶属于WindowOrWorkerGlobalScope的方法 (待填坑..)
但是在参考链接中的方法更佳,使用setInterval
会加入新的事件循环? Javascript 单线程模型 Event Loop 机制
//记录总的文件大小,使用一个`count`计数来判断异步结束
count = filenames.length;
for (i = 0; i < filenames.length; i++) {
fs.stat("./" + filenames[i], function (err, stats) {
totalBytes += stats.size;
count--;
if (count === 0) {
console.log(totalBytes);
}
});
}
从这个例子中,我们可以学到一点:并发运行的相同异步函数如果协作完成任务,需要添加计数代码判断执行状态,并且把所有异步函数完成后执行的代码放在判断条件的语句块里
前面的关卡好不容易闯过了后,兴高采烈的抓到了数据,写到了json里,可是一打开一开,gg,股票名称的字段,全是乱码?,网上提示,直接看一下源网站的编码,浏览器打开一看头部,charset="gb2312"
,难怪...
参考链接:
request库使用时, gb2312、GBK中文乱码解决方法
也就是引用iconv-lite
包,对返回的gb2312
的body
进行一下转码,Iconv.decode(body, 'gb2312').toString()
,这样就可以了
参考官方文档:
Upgrading MySQL on Windows,了解自己按哪种方式升级,我的是Upgrading MySQL Using the Windows ZIP Distribution
之后开始数据备份,Database Backup Methods
选择备份的方法, 我用的是Making Backups with mysqldump
,去查看mysqldump
的用法,mysqldump — A Database Backup Program文档比较多,我直接看的:Using mysqldump for Backups
// 直接使用命令行,报错 `Got error: 1045: Access denied for user 'ODBC'@'localhost' (using password: NO)`
mysqldump --all-databases > dump.sql
在网上找到Mysql备份还原数据库之mysqldump实例及参数详细说明
// 成功
mysqldump -u root -p --all-databases > dump.sql
选用傻瓜版:msi
,安装过程有一个注意事项,因为选的是Custom
,但是在后来的界面中一直打开的mysql server
都是最新版的8.0
,而且安装到某个界面还没有next
弹出...,后来才发现在Custom之后的选择界面有filter
选项,点开,里面就可以选择各种版本的server了
进入mysql数据库,使用source
命令:
source E:\xxx.sql
起因,妹子问的实习的公司连不上网,只有公司电脑连有线才可以,但是她在输ip地址从192.168.101.100
到192.168.101.254
一个个试(已经试到206),还是连不上网怎么办?
其实我对这个连不上网的问题真的好菜啊...,仅有的一次还是利用192.168.1.1
(还是什么去了..)登录上路由器,然后路由器密码还是贼简单,登上去了,就改了一个路由器的名字,开心了半天,然后就没有然后了...
回到正题,于是赶快google,知乎搜,还是不知道怎么做,就知道了一个DHCP
和静态ip
的名词.. 以及看到网友推荐了一本书,网络是怎样连接的,mark一下了
接着只好很丢脸的说,我不会啊,但是妹子说的从192.168.101.100
到192.168.101.254
一个个试,却留下了印象,就是,我们会用ping来测试网络是不是畅通,那么有没有一种方法能让自动的ping呢?
也就是今天自己学会的bat脚本
:
刚开始搜到这个:shell脚本实现网络连接的检测,这里面的思路就用循环从0到254,依次ping,很好,不过这是shell脚本,也就是在我的电脑上装了git-bash是可以运行的,但是妹子的电脑是没有的,也就是要转化成bat脚本啊,于是坑就来了
bat脚本的格式
,语法
问题:
@echo off ::开头,不显示后续命令行及当前命令行
set var_name = "hello" ::set来定义变量
echo %var_name% ::echo用于输出,变量取值用%var%
for /l %%i in (1,1,254) ::递增循环的示例 /l表示带开关,此处的变量是%%i
do (
:: code here
)
于是代码初步这样:
@echo off
::Ping网段所有IP
set ip="192.168.0."
for /l %%i in (1,1,254)
do (
ping -c 2 %ip%%%i |grep -q 'ttl=' && echo "%ip%%%i yes"|| echo "%ip%%%i no"
)
::yes正常,no主机不存在或不正常
pause
遇到的麻烦:
一闪而过...,应该是语法错误了,直接在cmd
中输入ping
,根本没有-c
的参数,而且grep
是Search for PATTERN in each FILE or standard input
,都去掉,依然一闪而过...
后来改成for /l %%i in (1,1,254) do ( ping %ip%%%i && echo "%ip%%%i yes"|| echo "%ip%%%i no" )
,写成一行可以,但报
错误的参数 1。
""192.168.0." 1 no"
在循环中拼接字符串,ping %ip%%%i
难道不可行?
在批处理文件在循环中拼接字符串,为什么结果不对啊问题中发现也有人遇到过,是需要设置环境变量延迟,加上setlocal enabledelayedexpansion
,并变成ping !ip!%%i
,可还是报同样的错误
难道是%%i
是数字类型,而ip是字符串类型根本不行?
在bat批处理脚本中,怎样将for语句中的%%i当作字符串处理?做类似于%str:~1,5%之类的操作?
可以用在循环中在设一个变量等于%%i的方法,即set num= %%i
,ping !ip!!num!
,结果没了错误参数,变成
""192.168.0." 1 yes"
这到底好没好呢...
同时又有提到字符串拼接的批处理用的是set /a num+=1
,set str=!str! %%i
,再在cmd批处理中set /a和set /p的区别介绍,了解到
/P 命令行开关允许将变量数值设成用户输入的一行输入
/a 是指定一个变量等于一串运算字符
彩蛋是这里面的实例2竟然有ping的示例代码
@echo off
set a=1
:start
echo %a%
ping 172.19.5.%a% -w 1 -n 1|find /i "Lost = 1"&&set c=1||set c=0
if %c%==0 (echo 172.19.5.%a% >>IP.txt)
set /a a=%a%+1
if %a%==255 exit
goto :start
利用goto
变成一个do...while
的结构,而且巧妙的用172.19.5.%a%
避免了之前的字符串拼接,最后还能把ping成功的ip写入txt
自己粘过来试,仍不成功...因为明明在我的电脑上172.19.5.x
都是ping不通的,却也全部写入了txt文件
再次查看ping命令:发现-w
为等待每次回复的超时时间(毫秒),这里设置为1,-n
为要发送的回显请求数,而find
,作者是想找到Lost=1
的ping不通的,但是我的是中文...,设为丢失=1
就好了:
1
数据包:已发送 = 1,已接受 = 0, 丢失 = 1 (100%丢失)
完美!
还有一种方式,之前看到设置超时为1,觉得是超时太断所致,即使是ping通的也会被判断为错误的,就直接改成,去掉find
,并需要把判断条件改成%c%==1
ping 192.168.101.%a% -n 1 && set c=1 || set c=0
if %c%==1 (echo 192.168.101.%a% >>IP.txt)
这样也是可行的,但是每次都会输出一大堆的ping的回显消息了
其实过程中还有,各种报ECHO
处于关闭状态的错误等,从下午到晚上,也算是第一次知道了shell编程
是什么,以及借此好像阴差阳错的懂了一点点linux
的强大
最后希望自己慢慢的不要那么菜吧哈哈
还有部分的参考连接:
Tomorrow, in a very real sense, your life -- the life you another from scrath on your own --begins
How will you use your gifts
? What choices
will you make? What inertia be your guide
, or Will you follow your passions
?
Will you follow dogma
, or Will you be original
? Will you choose a life of ease
, or a life of service and adventure
?
Will you wilt under criticism
, or Will you follow yoour convictions
?
Will you bluff it out when you're wrong
, or Will you apologize
?
Will you guard your heart
against rejection, or Will you act when you fall in love
?
Will you play it safe
, or Will you be a little bit swashbuckling
?
When it's tough
, Will you give up
, or Will you be relentless
?
Will you be a cynic
, or Will you be a builder
?
Will you be clever at the expense of others
, or Will you be kind
?
I will hazard a prediction, when you are 80 years old
, and in a quiet moment of reflection narrating for only yourself, the most personal version of your life story.
the telling that will be most compact and meaningful will be the series of choices you have made
,
in the end, We are our choices, Build yourself a great story.
艺无止境,功不唐捐