Coder Social home page Coder Social logo

blog's Introduction

Hi there 👋

blog's People

Contributors

zhangziang avatar

Watchers

 avatar  avatar

blog's Issues

分布式瞎记录

  1. zookeeper 可以用于分布式锁、命名服务、解决分布式一致性?
  2. zookeeper 本身是有主从的,zookeeper 使用 zab 协议解决分布式一致性问题。

使用 flex 实现纵向布局填充屏幕

想要实现页面中 header + content 占满且仅占满整个屏幕,其中 header 的高度固定,container 的高度自适应。下面给出两种实现方法(其实有更多种,通过搜索可以查到)。

calc 方法计算高度

这种方法要求知道 header 的 hight, 给 content 的 height 设置为 calc(100%-header_hight); 我想要使用 calc(100vh - header_hight); 来实现时,发现会比预期多出 12px,还没去找问题出在哪里。

flex 方法

利用 flex-grow 的特性,让 content 填充父元素的剩余空间,另外设置 overflow-y,避免 height 增长。

外部设置为

display: flex;
flex-direction: column;
height: 100%;

header 无需做特殊设置。

content 设置为

flex-grow:1;
overflow-y:scroll;

JavaScript 中异步的通俗理解

对 golang 中的异步比较熟悉,借助 golang 中的异步来理解 JavaScript 中的异步。

golang 中实现异步主要手段是使用 go 关键字 开启一个异步协程,通过 channellockwaitGroup 等手段做协程间的通信。

JavaScript 中最常用的异步是异步 http 请求,即 XMLHttpRequest(xmr)。首先需要明确的是 JavaScript 提供的 xmr 就是一个异步方法,相当于在 golang 中 go httpRequest()。在 xmr 请求结束后需要对请求结果做处理,在 golang 中比较简单,自己写一个用于异步的方法即可。在 JavaScript 中提供了三种方式来做异步结果处理。

  1. 回调

  2. then

  3. async & await

技术杂记

Python 与 Go 中切片复制的不同

python 中通过切片赋值 slice,是拷贝,而 go 中通过切片赋值 slice 是引用。

a = range(5)
b = a[:2]
b[0] = 1
print(a)
print(b)
# 输出 
# 0,1,2,3,4
# 1,1
func main() {
	a := []int64{1, 2, 3, 4}
	b := a[:2]
	b[0] = 0
	fmt.Println(b)
	fmt.Println(a)
}
// 输出
// 0,2
// 0 2 3 4

块作用域

go 是有块作用域的,即大括号包含的代码。python 和 javascript(var 声明)没有块作用域。 在 if、for 中声明的变量可以在外部使用。JavaScript 的 ES6 提供了 let 关键字来在块作用域中声明仅在块中有效的变量(let 特殊的一点是 for 循环中 for(let x= 0;x<10;x++) x 每次循环都声明一次,循环中的闭包引用 x,每次都是不同的 x)。

闭包

函数依然持有对该作用域的引用,这个引用就叫做闭包。

Go 中 json 和 gorm 所接受的 dst 参数,必须是一个引用,必须不是 nil

Go 的 interface

interface 的内存结构是存储分两部分,首先存了真是类型,存储了值(值如果是32位可以存储下来的话),存储了值的地址,interface的赋值是 copy。

golang 项目应该放到 GOPATH/src 吗?

两种情况

  1. 如果你的项目使用了 go mod,项目代码不需要放到 GOPATH/src,go mod init 的时候需要制定package go mod init [pack name]
  2. 如果你的项目没有使用 go mod,项目代码需要放到 GOPATH/src 中。

一个通俗理解:

当没有使用 go mod 时,项目代码在编译时遇到 import 时,通过 GOPATH 去查找相关引用,为了能找项目本身对自己的引用,需要将项目放到 GOPATH/src 下。

当使用 go mod时,项目代码在编译时查找包时通过 GOPATH/pkg/mod。我理解通过 go mod 可以知道哪些引用是项目本身(go.mod 文件中指定了当前项目的 module),因此不存在查找自身依赖出现问题。

Go 中的 type 相同判断和转换

类型声明

  1. 别名(alias) type A = B
  2. 定义(Type definitions) type A B

类型相同判断

https://golang.org/ref/spec#Type_identity

首先,定义类型总是与其他类型不相同。其次,如果两个类型的底层类型(underlying type)在字面和结构上是相同的,那么他们认为他们是相同类型。

字面和结构上是相同的具体:

  1. 数组,相同的元素类型和长度
  2. 切片,相同的元素类型
  3. struct,字段相同的顺序,字段名字、类型、tag 相同
    ...

underlying type

Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration.

如果类型是预定义类型(int8、int32、string...)或者 literal 类型

literal 类型

LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
SliceType | MapType | TypeName .

type A string
type B A
type C []string
type D []A

A 和 B 和 string 的 underlying type 是 string,C 的 underlying type 是 []string,D 的 underlying type 是 []A

赋值

https://golang.org/ref/spec#Assignability

可以赋值的条件: (类型X赋值给类型T)

  1. 相同类型可以赋值
  2. 两个底层类型相同,且至少有一个不是 defined 类型

需要注意的是,所有的数字类型都是 defined 类型,因此,下面这种情况需要强转

type MyInt int
var x int32
x  = 1
var y MyInt
y = MyInt(x)
  1. T 是 interface,X 实现了 T 的所有方法
  2. X 是双向 chan,T 是 chan,且 X 和 T 的元素类型相同,且X和T至少一个不是 defined 类型
  3. var z T = x, x 是 nil,T 是指针、slice、map 、 interface
  4. var z T = x, x 是可以用 T 表示的常数

类型转换

https://golang.org/ref/spec#Conversions

t := T(x)

可以转换的条件是:

  1. x 是可赋值到类型 T 的
  2. 除了 struct tag 外,x 的类型和 T 拥有相同的 underlying types
  3. 除了 struct tag 外,x 的类型和 T 都是指针类型(不是 defined type),且拥有相同的 underlying types
  4. 整形和浮点可以转换
  5. 复数类型可以转化
  6. 整形、[]byte、[]rune 可以转化为 string
  7. string 可以转化为 []byte、[]rune
  8. 4~7应该指的都是underlying type

MySQL 问题与解释

order by created_at desc limit 2,1; 表现不符合预期

首先不加 limit 查到的数据,然后加上 limit 发现取到的数据不是全量结果的相应值。原因是 order by 中的字段存在相同的值,导致结果有可能受到影响。不确定 order by 字段是否是唯一的,可以增加 order by id。

mysql 相关文档

在 read commit 隔离级别中的 select 与 update

在 rc 隔离级别中,事务中可以读取到已经提交事务对行的更新,读取不到未提交事务对行的更新。貌似是通过快照来实现,未确定。reference: https://dev.mysql.com/doc/refman/5.7/en/innodb-consistent-read.html

在 rc 隔离级别下,update 会获取到写锁,select 不需要锁,所以两个并行事务中,对行的update 不影响另一事务对同一行的 select。可以手动为 select 选择锁,select for update 获取写锁,select lock in share mode获取读锁。

基于以上,在扣除额度的场景下,我们可以写入如下两种 sql。

// 1 获取余额时就加上写锁,完成扣除,update 余额
select balance from account where id = 1 for update;
balance_new = balance -1;
update balance set balance = balance_new where id = 1;
// 2 将扣除余额的动作写在 update 中,有可能不符合扣款条件导致 rowaffect = 1
update account set balance = balance - 1 where balance > 0 and id = 1;

要避免的是直接 select,计算新余额,update 到新余额,这样无法保证并发一致性。

另外,在编写代码使用事务时,要尽量保证事务最短,避免事务过长,有可能存在锁等待等问题。

MySQL 是怎么存储数据的

MySQL 中通过索引组织数据,主键(聚簇索引)索引上的叶子节点包含数据,辅助索引(非聚簇索引)的叶子节点上包含主键值。索引的数据结构是B+ 树,具体数据存储在叶子节点,叶子节点之间有双向指针。对于 InnoDB 来说,叶子节点的数据是一页,一页默认是16k,可以通过参数对页的大小进行配置。一页中至少存在两条数据(如果有超过了将数据存放在溢出页)。

联合索引的 key 就是多个键的值。

连续的页组成区,一个区1MB,包含64个连续的页,数据库一次向系统申请 4~5 个区。

MySQL 中使用索引的一些技巧

binlog、redo log、undo log

  1. binlog 在 Mysql的上层产生,redo 与 undo产生在存储引擎, 是 innodb 存储引擎特有的。
  2. binlog 记录的是执行语句,只记录已经提交事务的执行语句。
  3. redo log 记录的是页的变化,记录所有的变换,用于在宕机等情况下进行恢复。
  4. redo log 存储在文件系统的日志文件中。
  5. undo log 用于回滚,在执行事务、语句失败以及 rollback 时。
  6. undo log 存储在共享表空间的 undo 段。
  7. undo log 的回滚是通过生成相反的sql进行恢复。
  8. undo log 用于实现 MVCC。
  9. undo log 同时也会产生 redo log。

python 中的作用域

  1. 函数级别的 local 作用域
  2. 没有块级作用域
  3. Local(局部) Enclosing(闭包) Global(全局) Built-in(内置) 四级作用域
  4. 修改闭包的变量需要使用 nonlocal 声明 nonlocal x
  5. nonlocal 会向上回溯,直至找到对应的变量
  6. 修改全局变量需要使用 global 声明 global x

Go 获取函数调用栈信息

func getTrace() string {
   pcs := make([]uintptr, 100)
   runtime.Callers(0, pcs)
   trace := new(strings.Builder)
   frames := runtime.CallersFrames(pc)
   for {
      frame, more := frames.Next()
      trace.WriteString(fmt.Sprintf("file:%s,line:%d, name:%s[\\n]", frame.File, frame.Line, frame.Function))
      if !more {
         break
      }
   }
   return trace.String()
}

👆代码中使用了 callerFrames 获取 pc 对应的栈信息,最开始使用 FuncForPC 获取到的结果不符合预期。在 runtime.Callers 文档中指出了不能迭代 pc

To translate these PCs into symbolic information such as function
names and line numbers, use CallersFrames. CallersFrames accounts
for inlined functions and adjusts the return program counters into
call program counters. Iterating over the returned slice of PCs
directly is discouraged, as is using FuncForPC on any of the
returned PCs, since these cannot account for inlining or return
program counter adjustment.

runtime 包中有一个 Caller 方法可以获取单条栈信息,接受单个参数 skip,需要注意的是 CallerCallers 中参数 skip 的含义不同,Callerskip = 0 时,返回调用 Caller 函数的信息。Callersskip = 0 时,返回从 Callers 函数内部调用开始。

cs61a 笔记

Currying 柯里化

将接受多个参数的函数转变为多个接受单个参数的函数。

We can use higher-order functions to convert a function that takes multiple arguments into a chain of functions that each take a single argument. More specifically, given a function f(x, y), we can define a function g such that g(x)(y) is equivalent to f(x, y). Here, g is a higher-order function that takes in a single argument x and returns another function that takes in a single argument y. This transformation is called currying.

CSRF 攻击、同源策略、CORS

什么是 CSRF 攻击

这方面为网上资料很多,原理是访问目标网站时浏览器会带上目标网站的 cookie。一般情况下会将用户验证信息存储在 cookie 中,CSRF 攻击利用这一点,在其他网站构造目标网站的请求(form 表单自动提交等)实现一些操作。如果目标网站本身有漏洞,也可以利用漏洞在目标网站上传能触发请求的内容,但是这部分应该属于 XSS 攻击。

防范 CSRF 攻击

防范 CSRF 攻击的常用手段是在 form 表单中增加隐藏 token 字段,增加一道验证手段, token 可以通过页面渲染时下发。因为 CSRF 攻击利用了 cookie,所以如果将验证信息放到 Header 中应该也可以防范攻击。(请求由 js 发起)

什么是同源策略 SOP

同源是指协议、域名、端口都相同。

同源策略主要目的是限制 js 处理不同源的返回结果。ajax 向其他域名发送请求被同源策略阻拦时请求已经发送。

css、js、img、form 不受同源限制。

同源策略为什么不能防止 CSRF 攻击

因为 form 不受同源限制,且 ajax 请求也会被发送。

CORS 是什么

为了解决同源限制的问题,提出了 CORS 标准。服务端 Response Header 中设置 Access-Control-Allow-Origin 等来允许跨站请求。CORS 中又分为简单请求和复杂请求。复杂请求会有先进发送一个 OPTIONS 请求。

简单请求满足一下条件:

  1. GET、HEAD、POST 请求
  2. 允许的 Header:
  3. 允许的 Content-Type:text/plain、multipart/form-data、application/x-www-form-urlencoded

其他复杂请求浏览器会先发送一个 OPTIONS 预检请求获取 CORS 策略。在 w3c 标准中要求预检请求要返回 2xx

If the response has an HTTP status code that is not in the 2xx range.
Apply the network error steps.

js 请求时想要带上 cookie 的话,需要配置 withCredentials=true

Response Header:

  1. Access-Control-Allow-Origin,值为 或 *,不能设置多个 origin,如果是 credentials 为 true 时 (带 cookie)不能是 *
  2. Access-Control-Allow-Methods,支持多个方法 POST, GET, OPTIONS
  3. Access-Control-Allow-Headers,指明允许携带额外的 header
  4. Access-Control-Allow-Credentials,值为 true,允许 credentials 为 true 的请求
  5. Access-Control-Max-Age,预检请求的过期时间,单位秒

具体可以查看 MDN 文档w3c 文档

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.