☻Blog("Laziji")

System.out.print("辣子鸡的博客");

重定向

重定向的分为两种301302, 这两种使用起来感觉差不多, 但是对搜索引擎来说是有区别的

  • 301 表示永久重定向, 搜索引擎收到301响应时会把旧的地址的权值传给新的, 所以当网站更改域名或者网站内部资源url改变时应该使用301重定向
  • 302 表示临时重定向, 顾名思义就是告诉搜索引擎, 这个新地址只是临时用一用

权值分散

当一个网站有多个域名的时候, 据个人经验, 应当把所以域名都重定向到一个主域名上, 例如abc.comwww.abc.comhome.abc.com, 这三个都指向一个网站, 会造成权值的分散

更坏的情况是别人把他的域名定到你的网站上, 让你的网站来养着他的域名, 等时机成熟, 别人把域名一收, 你的网站就突然流失了一大部分流量

所以最好就是在代码中(或者在容器中)对域名进行重定向, 检测请求中的域名, 若不是主域名如www.abc.com就全部301重定向过来

springboot中的实现

完整代码
HostInterceptor.java

编写一个通用的拦截器, 首先检测请求方式, 只对get请求进行重定向, 因为get请求来自浏览器, 会自动对301重定向进行页面跟随。 之后检查域名若不在白名单中则进行重定向

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class HostInterceptor implements HandlerInterceptor {

private String redirectHost;
private Integer redirectPort;
private Set<String> hostWhitelistSet = new TreeSet<>();

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {

if (redirectHost == null) {
return true;
}

if (!"get".equals(request.getMethod().toLowerCase())) {
return true;
}

String host = request.getHeader("host");
if (hostWhitelistSet.contains(host)) {
return true;
}

response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
StringBuilder url = new StringBuilder();
if (request.isSecure()) {
url.append("https://");
} else {
url.append("http://");
}
url.append(redirectHost);
if (redirectPort != null && redirectPort != 80) {
url.append(':').append(redirectPort);
}
url.append(request.getRequestURI());
String queryString = request.getQueryString();
if (queryString != null) {
url.append('?').append(queryString);
}
response.setHeader("location", url.toString());
return false;
}

public void addHostWhitelist(String host) {
if (host == null) {
return;
}
hostWhitelistSet.add(host);
}

public String getRedirectHost() {
return redirectHost;
}

public void setRedirectHost(String redirectHost) {
if (redirectHost == null) {
return;
}
this.redirectHost = redirectHost;
hostWhitelistSet.add(redirectHost);
}

public Integer getRedirectPort() {
return redirectPort;
}

public void setRedirectPort(Integer redirectPort) {
if (redirectPort == null || redirectPort < 1 || redirectPort > 65535) {
return;
}
this.redirectPort = redirectPort;
}
}

使用如下, 在启动类中配置拦截器, 我们可以在白名单中配置主域名(主域名自动加入白名单)和localhost(用于本地开发)

1
2
3
4
HostInterceptor hostInterceptor = new HostInterceptor();
hostInterceptor.setRedirectHost("www.abc.com");
hostInterceptor.addHostWhitelist("localhost");
registry.addInterceptor(hostInterceptor).addPathPatterns("/**");

AlphaZero的设计十分精妙, 模拟人的思维方式, 并且相比上一代的AlphaGo去除了人类棋谱的训练, 不仅更加精简, 而且棋力更上了一个层次
设计主要分为两部分

神经网络(走子价值网络)

神经网络在其中的作用相当于人的棋感, 根据当前局面, 不进行推演, 直接判断哪里是好棋哪里是坏棋

输入

谷歌的AlphaGo Zero采用的19 * 19 * 17的输入
即一个19 * 19代表当前局面的黑棋或白棋的位置, 0代表没有, 1代表有
所以一个完整的局面需要19 * 19 * 2来表示, 输入包含8个历史输入, 因为围棋中存在打劫, 当前可选位置与历史有关, 所以历史局面是必须的
除此之外还有一个参数就是当前局面是哪一方走子, 用0或1表示, 为了方便, 把0或1扩展到19 * 19的平面, 即全为0或1的平面
一共2*8+1, 17个平面作为神经网络的输入

这里以无禁手五子棋为例, 在五子棋中输入可以进行简化, 因为五子棋的下子可以认为只与当前局面有关, 与历史无关
可以采用15 * 15 * 3的输入

输出

大小为361pi, 代表每个位置下子的概率
以及z当前局面的价值, 在[-1,1]之间

中间层

中间层包括一个卷积块, 之后连接一个残差网络, 然后残差网络的输出作为策略头(走子概率), 和价值头(胜率)的输入, 两个头都是一个卷积层跟上一个全连接层
AlphaZero中使用了多层残差网络来获得更强的学习能力, 但是在普通PC上自我对弈时过于缓慢, 可以尝试减少层数, 或者去掉残差网络
可以先实现, 之后再优化的时候适当加入

MCTS(蒙特卡洛树搜索)

MCTS相当于人在下棋过程中的推演过程, 利用MCTS改善每个局面的走子概率, 就像人可以通过推演发现一些在当前局面看起来不是很好的棋
MCTS分为这几个过程

A 选择

从当前局面节点(通过N,P,V计算所有节点的价值)选择价值最大的节点, 最为下一个节点

B 扩展

若当前局面没有搜索过, 使用神经网络预测当前局面的走子概率

C 价值回传

不断进行AB, 直到达到叶子节点, 棋局结束, 把胜负结果回传, 并将节点加入神经网络进行训练

0%