JaguarJack's Blog

做人呢最重要的就是开心

0%

遇到的题目

使用 Channel 进行任务编排的题,你可以尝试做一下:有四个 goroutine,编号为 1、2、3、4。每秒钟会有一个 goroutine打印出它自己的编号,要求你编写一个程序,让输出的编号总是按照 1、2、3、4、1、2、3、4、……的顺序打印出来。

阅读全文 »

什么是字节对齐

现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。

阅读全文 »

问题

项目中导出 Excel 的时候,由于文件名设置的是中文字符串,在 Google 浏览器是正常的导出,文件名不会出现乱码,但是在 Edge/IE 浏览器下就会出现乱码的情况。Google 一下你会搜到很多答案,当然很多都是不靠谱的,最后问题是解决了。但是遇到这个问题的人并没有说明为什么会出现这个问题,究其根源,看博客的意思应该是从墙外找到的答案。

解决

解决这个很简单,但是需要做的就是去了解为什么要这样做,下面是解决办法。

1
2
3
4
5
6
7
8
9
10
11
function encodeFileName($filename) {
$ua = strtolower($_SERVER('HTTP_USER_AGENT'));

//判断是否为IE或Edge浏览器
if(preg_match('/msie/', $ua) || preg_match('/edge/', $ua)) {
//使用 urlencode 对文件名进行重新编码
return str_replace('+', '%20', urlencode($filename));
}

return $filename;
}

其实问题解决是很简单的,使用urlencode函数就可以了。下面慢慢道来。

这篇文章主要记录 Nginx 一些学习和笔记。还有遇到的问题。

nginx.conf 文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
... # 全局模块

# events 模块
events {
....
}

# http块
http {
# http 全局块
...
# server 块
server
{
# server 全局块
...
# location 块
location [PATTERN]
{
...
}
}
}

由上面以大括号为分割 Nginx.conf 可分为三大块全局块, events, http。其中 http 模块里面有分为 全局块, server 两个块。server 可以有多个。server 里面又分为 全局location 两个模块。location 也是可以有多个。在 Nginx 使用方面,大多数都体现在配置文件。应用方面也体现在配置了,当然 Nginx 配置是很丰富多样的。

全局模块

全局模块是默认配置文件开始到 events 这一块内容,主要设置一些 Nginx 运行指令,通常包括 Nginx 运行的用户/组,worker proccess 数,Master 进程 PID 存储路径,日志的存放路径以及配置文件的引入等等。

events 模块

events 模块主要是 Nginx 与用户链接的设置。包括设置事件驱动模型和每个 worker proccess 允许的最大链接数目,这部分设置对 Nginx 的性能影响很大,主要体现事件驱动上。

Http 模块

Http 模块是 Nginx 服务的重要部分,代理,缓存和日志等绝大数功能和第三方模块都是放在这个模块中。

Http全局块

Http 全局块中配置的指令包括文件引入,MIME-Type 定义,日志自定义,是否使用 sendfile 传输文件,链接超时时间,但链接请求上限等。

Server 模块

Http 块中可以包含多个 Server 模块,每个 Server 模块对应着一台虚拟机,可以为多台主机提供服务,注意这里是一组逻辑上关系。

Server 全局模块

Server 全局模块提供一些基础功能, 包括虚拟机的监听配置和配置虚拟机的名称或者 IP 地址。

Location 模块

Server 模块的大多数功能都在 Location 中实现,其实整个 Nginx 配置重要的配置都在这块,location 主要对 Nginx 的接收的 uri 进行匹配,对特定的请求进行处理,地址定向,数据缓存和应答等控制功能都是在这部分实现,第三方模块也提供了这块的功能

时序图

用流程图表示可能更加明显,来看一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
graph LR;
Nginx.conf-->id1{全局模块};
Nginx.conf-->id2{Event模块};
Nginx.conf-->id3{Http模块};
id1{全局模块}-->运行用户组;
id1{全局模块}-->workerProccess数目;
id1{全局模块}-->MasterPID存储路径;
id1{全局模块}-->日志存放路径;
id1{全局模块}-->配置文件引入;
id2{Event模块}-->事件驱动模型;
id2{Event模块}-->允许最大链接数目;
id3{Http模块}-->Http全局模块;
Http全局模块-->文件引入;
Http全局模块-->MIME-Type定义;
Http全局模块-->自定义日志;
Http全局模块-->sendfile传输文件;
Http全局模块-->链接超时;
Http全局模块-->链接请求上限;
id3{Http模块}-->Server模块;
Server模块-->Server全局模块;
Server全局模块-->虚拟机的监听;
Server全局模块-->配置虚拟机名称或者IP地址;
Server模块-->Location模块;
Location模块-->请求处理;
Location模块-->地址定向;
Location模块-->数据缓存;
Location模块-->请求应答;
Location模块-->反向代理;

问题一

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

解决

上来不由分说,先来一个 For 再说😄

1
2
3
4
5
6
7
8
9
10
11
12
func sumtotarget(nums []int, target int) []int {
l := len(nums)
for i, v := range nums {
r := target - v
for j:=i+1; j < l; j++ {
if r == nums[j] {
return []int{i, j}
}
}
}
return []int{}
}

完美成功运行了,哈哈。想想这样不行啊 O(n^2)。然后仔细想了一下,可以利用 map 的特性来处理,就有下面这一段代码。

1
2
3
4
5
6
7
8
9
10
11
12
func sumtotarget(nums []int, target int) []int {
numbers := make(map[int]int)
for i, v := range nums {
j, ok := numbers[v]
numbers[target - v] = i
if ok {
return []int{j, i}
}
}

return []int{}
}

第一刷,简单题都扛不住了。只能慢慢来了

问题二

Given a 32-bit signed integer, reverse digits of an integer.

Example 1:

Input: 123
Output: 321

Example 2:

Input: -123
Output: -321

Example 3:

Input: 120
Output: 21

Note:
Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

解决

注意的就是 int32 溢出的问题了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func reverse(x int) int {
var num int
for {
n := x % 10
if x == 0 && n == 0 {
break
}
x = x / 10
num = num * 10 + n
}
// -2147483648 到 2147483647
if num > math.MaxInt32 || num < math.MinInt32 {
return 0
}
return num
}

问题三

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

Example 1:

Input: 121
Output: true

Example 2:

Input: -121
Output: false

Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
Example 3:

Input: 10
Output: false

Explanation: Reads 01 from right to left. Therefore it is not a palindrome.

解决

这道题数字回文,其实和上面的反转是一个道理,就是比较反转后的数字和实参是否相等就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func isPalindrome(x int) bool {
if x < 0 {
return false
}
var num int
cache := x
for {
n := x % 10

if x == 0 && n == 0 {
break
}
x = x / 10
num = num * 10 + n
}
if cache == num {
return true
}

return false
}

问题

博客最近切换到了 hexo 博客, 目前用起来感觉很方便。很喜欢 markdown 写作。当然利用 Github Pages 也省下了一笔费用,某套路云的套路令人感到恶心。这里就不多说了。为什么要换评论呢?因为我使用的 next 主题的评论都不太合我的心意,Disqus 很好,但是广告太多,其他仿 git 的评论总觉得别扭,于是我也翻了找找看,发现了 utterance,觉得挺不错的,简洁风格也不缺失。所以就打算换这个了。

解决

hexo 的主题改起来还是很方便的,从配置开始,然后添加一小段的模块代码就可以了。标签也可以仿照其他文件,So Easy!开始动手吧。在这之前需要到 utterances app 申请一下,这样 utterances 才有权限访问你的仓库。

添加配置

找到 Next 主题的配置文件 _config.yml,配置随便你添加到哪里。你可以放在文件末尾或者可以和其他评论模块配置放在一块。

1
2
3
4
5
utterance:
enable: true
repo: #仓库名字
theme: #主题
issue-term: #映射配置

评论主题的 theme 选项如下:

  • github-light
  • github-dark
  • github-dark-orange
  • icy-dark
  • dark-blue
  • photon-dark

评论 issue-term 映射配置选项如下:

  • pathname
  • url
  • title
  • og:title
  • issue-number
  • specific-term

引入 Utterance 插件

_third-party\comments 文件夹下创建 utterance.swig 文件。写入代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
(function() {
// 匿名函数,防止污染全局变量
var utterances = document.createElement('script');
utterances.type = 'text/javascript';
utterances.async = true;
utterances.setAttribute('issue-term','{{ theme.utterance.issue-item }}')
utterances.setAttribute('theme','{{ themm.utterance.theme }}')
utterances.setAttribute('repo','{{ theme.utterance.repo }}')
utterances.crossorigin = 'anonymous';
utterances.src = 'https://utteranc.es/client.js';
// content 是要插入评论的地方
document.getElementById('gitment-container').appendChild(utterances);
})();
</script>

增加 comment 样式

找到 _partials\comments.swig 然后增加下面代码:

1
2
3
4
{% elif theme.utterance.enable %}
<div class="comments" id="comments">
<div id="gitment-container"></div>
</div>

还需要在 _third-party\comments\index.swig 添加如下代码

1
2
{% elif theme.utterance.enable %}
{% include 'utterance.swig' %}

以上就是整个配置过程。如果有任何问题可以在评论区留言。

问题

公司需要将老项目迁移, 由于之前的错误返回都是不规范的, 对于错误处理都是直接返回 200 http code。大量的使用这样的返回。

1
response()->json(200, ['msg'=>$msg])

已经没有办法更改了, 客户端都是根据接口的的业务代码 code 来判断的。但是在新的项目中严格规范使用异常抛出, 但是异常抛出后 http code 返回的是 500。导致测试通过不了, 没有办法只能修改。

解决

使用了异常抛出业务错误, 在 laravel 框架中, 异常都是统一处理的, 在 App\Exceptions\Handle 里面进行了全局处理。对于框架抛出的异常, 全部由它来处理。但是当你想要在 Handle 里面修改处理的时候, 你会发现并不会有任何效果。到底什么原因导致的呢?

在入口文件可以看到这么一段代码

1
2
3
4
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);

在这里进行了全局的异常服务注册, 这里先不关注异常在哪里处理的。既然实际是没有通过 Hanle 类处理, 猜测这里服务可能被 Dingo 重新注册过了。带着这个想法可以看一下 Dingo 的服务注册。在 Dingo\Api\Provider\DingoServiceProvider 看到了异常注册

1
2
3
4
5
6
protected function registerExceptionHandler()
{
$this->app->singleton('api.exception', function ($app) {
return new ExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], $this->config('errorFormat'), $this->config('debug'));
});
}

这里肯定会有疑问了, 这个单例模式也没有重新注册 Illuminate\Contracts\Debug\ExceptionHandler::class 这个类啊?没错, 因为 Dingo 接管了路由, 你实际使用的 \Dingo\Api\Routing\Router::class, 所以 Dispatch 的会由 Dingo 来执行。这里就不细说了。有兴趣的可以看一下 Dingo 的处理。
Dispatch 处理可以在 Dingo\Api\Dispatcher里面找到。来看一下代码处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected function dispatch(InternalRequest $request)
{
$this->routeStack[] = $this->router->getCurrentRoute();

$this->clearCachedFacadeInstance();

try {
$this->container->instance('request', $request);

$response = $this->router->dispatch($request);

if (! $response->isSuccessful() && ! $response->isRedirection()) {
throw new InternalHttpException($response);
} elseif (! $this->raw) {
$response = $response->getOriginalContent();
}
// 主要看这里的 exception 处理 这里就是接管的异常
} catch (HttpExceptionInterface $exception) {
$this->refreshRequestStack();

throw $exception;
}

$this->refreshRequestStack();

return $response;
}

先不用管这个接口类的异常, 来看看 Dingo 的 Handle 如何处理的。下面会提到处理为何这里是接口, 还有该如何修改。

你需要从 render 方法来是查找, 你最终会看到, 过程就不细讲了。

1
2
3
4
protected function getExceptionStatusCode(Exception $exception, $defaultStatusCode = 500)
{
return ($exception instanceof HttpExceptionInterface) ? $exception->getStatusCode() : $defaultStatusCode;
}

这里就和上面的接口类对应了, 为什么返回 500 呢?看这段代码已经一目了然了。如果不是实现了 HttpExceptionInterface 的异常类, StatusCode 都是返回 500。所以需要做的就很简单了, 实现 HttpExceptionInterface 就可以了。简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class BaseException extends \Exception  implements HttpExceptionInterface
{

public function getStatusCode()
{
return 200;
}

/**
* Returns response headers.
*
* @return array Response headers
*/
public function getHeaders()
{
return [];
}

这是一个 exception 基类, 需要的就是继承就可以了。这样就可以解决该问题了。

在使用 Laravel 框架的时候, 开发第三方服务的时候, 由于是本地开发, 所以 Https 回调的时候回出现这样的错误。那么该如何解决呢? 具体信息如下

cURL error 60: SSL certificate problem: unable to get local issuer certificate (see http: curl.haxx.se libcurl c libcurl errors.html)

为什么会出现这种错误?

由于敏感信息的传输通常在数字证书下进行。 该证书将有助于向收件人确认发件人实际上是他们声称的人。 数字证书由证书机构颁发。

当数字证书应用于服务器时,服务器上会安装可信证书颁发机构及其根证书的列表。 通过常规 HTTPS 进行的事务将恢复到此列表以进行通信。 但是,CURL 不遵守规则。 您需要告诉 Curl 有关 Ca 根证书的信息。

如何解决?

要解决该错误,您需要定义 CURL 证书颁发机构信息路径
要做到这一点,在此处下载最新的 curl 认可证书,
cacert.pem 文件保存在可到达的目标中。
然后,在 php.ini 文件中,向下滚动到找到 [curl] 的位置。
您应该看到注释掉了 CURLOPT_CAINFO 选项。 取消注释并将其指向 cacert.pem 文件。 你应该有这样的一行:

1
curl.cainfo =“证书路径\cacert.pem”

保存并关闭 php.ini。 重新启动您的网络服务器并再次尝试您的请求

如果未设置正确的位置,则会出现 CURL 77 错误。

安装 man 中文手册

在使用 mac 或者 linux 的时候,需要用到命令,而大量的命令含有大量 options,一般很难记住,使用 man 可以查看这些命令的 options,但对于英语薄弱的人来说,例如我,看起来还是有一定的困难,所以需要安装以下中文手册。
准备前,我们需要安装两个 package,前提你是使用了 brew 管理

1
2
> brew install automake
> brew install opencc

然后需要下载中文包。

1
2
3
4
5
6
> git clone  https://github.com/man-pages-zh/manpages-zh
> cd manpages-zh
> autoreconf --install --force
> ./configure
> sudo make
> sudo make install

等待编译完成之后,我们还需要配置一些东西。如果你之前没有更新 groff,需要先更新 groff,不然会出现乱码。

1
2
3
4
5
> brew install groff 
> echo "MANPATH /usr/local/share/man/zh_CN" >> /etc/man.conf
> echo "NROFF preconv -e UTF8 | /usr/local/bin/nroff -Tutf8 -mandoc -c" >> /etc/man.conf
> export alias cman='man -M /usr/local/share/man/zh_CN' // 你可以加入到环境变量里
> cman ls

这样就可以愉快的使用 man 中文手册啦