├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets └── Nginx.eddx ├── docs ├── README.md ├── coverpage.md ├── index.html ├── nginx-configuration.md ├── nginx-faq.md ├── nginx-introduction.md ├── nginx-ops.md ├── nginx-quickstart.md ├── package.json └── sidebar.md ├── examples ├── README.md ├── images │ ├── nginx-demo01.png │ ├── nginx-demo02.png │ ├── nginx-demo03.png │ ├── nginx-demo04(2).png │ ├── nginx-demo04.png │ ├── nginx-demo05.png │ └── nginx-demo06.png ├── javaapp │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── github │ │ │ └── dunwu │ │ │ ├── Main.java │ │ │ ├── filter │ │ │ └── CorsFilter.java │ │ │ ├── util │ │ │ └── IOObjectMapper.java │ │ │ └── web │ │ │ ├── controller │ │ │ ├── ApiController.java │ │ │ ├── HelloController.java │ │ │ └── IndexController.java │ │ │ └── dto │ │ │ ├── BaseResponseDTO.java │ │ │ └── MenuDTO.java │ │ ├── resources │ │ ├── spring │ │ │ └── spring-servlet.xml │ │ └── tomcat │ │ │ └── conf │ │ │ ├── server.xml │ │ │ └── web.xml │ │ └── webapp │ │ ├── META-INF │ │ └── MANIFEST.MF │ │ ├── WEB-INF │ │ └── web.xml │ │ └── views │ │ └── jsp │ │ ├── hello.jsp │ │ └── index.jsp ├── nginx-1.14.0 │ ├── conf │ │ ├── conf.d │ │ │ ├── demo01.conf │ │ │ ├── demo02.conf │ │ │ ├── demo03.conf │ │ │ ├── demo04.conf │ │ │ ├── demo05.conf │ │ │ └── demo06.conf │ │ ├── fastcgi.conf │ │ ├── fastcgi_params │ │ ├── koi-utf │ │ ├── koi-win │ │ ├── mime.types │ │ ├── nginx.conf │ │ ├── scgi_params │ │ ├── uwsgi_params │ │ └── win-utf │ ├── contrib │ │ ├── README │ │ ├── geo2nginx.pl │ │ ├── unicode2nginx │ │ │ ├── koi-utf │ │ │ ├── unicode-to-nginx.pl │ │ │ └── win-utf │ │ └── vim │ │ │ ├── ftdetect │ │ │ └── nginx.vim │ │ │ ├── ftplugin │ │ │ └── nginx.vim │ │ │ ├── indent │ │ │ └── nginx.vim │ │ │ └── syntax │ │ │ └── nginx.vim │ ├── docs │ │ ├── CHANGES │ │ ├── CHANGES.ru │ │ ├── LICENSE │ │ ├── OpenSSL.LICENSE │ │ ├── PCRE.LICENCE │ │ ├── README │ │ └── zlib.LICENSE │ ├── html │ │ ├── 50x.html │ │ └── index.html │ ├── nginx-start.bat │ ├── nginx-stop.bat │ └── nginx.exe ├── nginx.conf ├── reactadmin │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── serviceWorker.js ├── reactapp │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintrc │ ├── .gitattributes │ ├── .gitignore │ ├── config │ │ ├── app.config.js │ │ ├── webpack.config.base.js │ │ ├── webpack.config.dev.js │ │ └── webpack.config.prod.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── scripts │ │ └── build.sh │ └── src │ │ ├── common │ │ └── apiutils │ │ │ ├── ajaxCommon.js │ │ │ ├── apiCreator.js │ │ │ ├── errorUtils.js │ │ │ ├── fetchAJAX.js │ │ │ ├── index.js │ │ │ └── reqwestAJAX.js │ │ ├── components │ │ ├── index.js │ │ └── layout │ │ │ ├── Breadcrumb │ │ │ ├── Breadcrumb.jsx │ │ │ └── Breadcrumb.less │ │ │ ├── Content │ │ │ ├── Content.jsx │ │ │ └── Content.less │ │ │ ├── Footer │ │ │ ├── Footer.jsx │ │ │ └── index.less │ │ │ ├── Header │ │ │ ├── Header.jsx │ │ │ └── Header.less │ │ │ └── Sidebar │ │ │ ├── Sidebar.jsx │ │ │ ├── Sidebar.less │ │ │ └── antd.svg │ │ ├── containers │ │ ├── Core │ │ │ ├── CoreContainer.jsx │ │ │ ├── CoreContainer.less │ │ │ └── package.json │ │ └── Root │ │ │ ├── ReduxDevTools.jsx │ │ │ ├── RootContainer.dev.jsx │ │ │ ├── RootContainer.jsx │ │ │ └── RootContainer.prod.jsx │ │ ├── index.jsx │ │ ├── redux │ │ ├── actions │ │ │ ├── auth.js │ │ │ └── menu.js │ │ ├── constants │ │ │ ├── authActionType.js │ │ │ ├── commonActionTypes.js │ │ │ └── menuActionType.js │ │ ├── middlewares │ │ │ └── promiseMiddleware.js │ │ ├── reducers │ │ │ ├── auth.js │ │ │ ├── index.js │ │ │ └── menu.js │ │ └── store │ │ │ ├── configureStore.dev.js │ │ │ ├── configureStore.js │ │ │ └── configureStore.prod.js │ │ ├── routes │ │ └── index.jsx │ │ ├── utils │ │ ├── asyncLoadHOC.js │ │ ├── authHOC.jsx │ │ ├── http.js │ │ └── index.jsx │ │ ├── views │ │ └── pages │ │ │ ├── home │ │ │ ├── Home.jsx │ │ │ ├── Home.less │ │ │ └── logo.svg │ │ │ ├── login │ │ │ ├── Login.jsx │ │ │ ├── Login.less │ │ │ ├── bg.jpg │ │ │ └── login-logo.png │ │ │ ├── mail │ │ │ └── Mailbox.jsx │ │ │ └── user │ │ │ ├── User.jsx │ │ │ └── User.less │ │ └── webapi │ │ ├── mock │ │ ├── index.js │ │ ├── menu.js │ │ └── user.js │ │ ├── package.json │ │ └── webapi.js └── scripts │ ├── build-javaapp.bat │ ├── build-reactadmin.bat │ ├── build-reactapp.bat │ ├── demo01-start.bat │ ├── demo02-start.bat │ ├── demo03-start.bat │ ├── demo04-start.bat │ ├── demo05-start.bat │ ├── demo06-start.bat │ └── startup.sh └── prettier.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig 用于在 IDE 中检查代码的基本 Code Style 2 | # @see: https://editorconfig.org/ 3 | 4 | # 配置说明: 5 | # 所有文件换行使用 Unix 风格(LF),*.bat 文件使用 Windows 风格(CRLF) 6 | # java / sh 文件缩进 4 个空格,其他所有文件缩进 2 个空格 7 | 8 | root = true 9 | 10 | [*] 11 | end_of_line = lf 12 | indent_size = 2 13 | indent_style = space 14 | max_line_length = 120 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.{bat, cmd}] 20 | end_of_line = crlf 21 | 22 | [*.{java, gradle, groovy, kt, sh}] 23 | indent_size = 4 24 | 25 | [*.md] 26 | max_line_length = 0 27 | trim_trailing_whitespace = false 28 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # plan text 4 | *.txt text 5 | *.java text 6 | *.scala text 7 | *.groovy text 8 | *.gradle text 9 | *.xml text 10 | *.xsd text 11 | *.tld text 12 | *.yaml text 13 | *.yml text 14 | *.wsdd text 15 | *.wsdl text 16 | *.jsp text 17 | *.jspf text 18 | *.js text 19 | *.jsx text 20 | *.json text 21 | *.css text 22 | *.less text 23 | *.sql text 24 | *.properties text 25 | 26 | # unix style 27 | *.sh text eol=lf 28 | 29 | # win style 30 | *.bat text eol=crlf 31 | 32 | # don't handle 33 | *.der -text 34 | *.jks -text 35 | *.pfx -text 36 | *.map -text 37 | *.patch -text 38 | *.dat -text 39 | *.data -text 40 | *.db -text 41 | 42 | # binary 43 | *.jar binary 44 | *.war binary 45 | *.zip binary 46 | *.tar binary 47 | *.tar.gz binary 48 | *.gz binary 49 | *.apk binary 50 | *.bin binary 51 | *.exe binary 52 | 53 | # images 54 | *.png binary 55 | *.jpg binary 56 | *.ico binary 57 | *.gif binary 58 | 59 | # medias 60 | *.mp3 binary 61 | *.swf binary 62 | 63 | # fonts 64 | *.eot binary 65 | *.svg binary 66 | *.ttf binary 67 | *.woff binary 68 | 69 | # others 70 | *.pdf binary 71 | *.doc binary 72 | *.docx binary 73 | *.ppt binary 74 | *.pptx binary 75 | *.xls binary 76 | *.xlsx binary 77 | *.xmind binary 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------- 2 | # more gitignore templates see https://github.com/github/gitignore 3 | # --------------------------------------------------------------------- 4 | 5 | # ------------------------------- java ------------------------------- 6 | # compiled folders 7 | classes 8 | target 9 | logs 10 | .mtj.tmp/ 11 | 12 | # compiled files 13 | *.class 14 | 15 | # bluej files 16 | *.ctxt 17 | 18 | # package files # 19 | *.jar 20 | *.war 21 | *.nar 22 | *.ear 23 | *.zip 24 | *.tar.gz 25 | *.rar 26 | 27 | # virtual machine crash logs 28 | hs_err_pid* 29 | 30 | # maven plugin temp files 31 | .flattened-pom.xml 32 | package-lock.json 33 | 34 | 35 | # ------------------------------- javascript ------------------------------- 36 | # dependencies 37 | node_modules 38 | 39 | # temp folders 40 | build 41 | dist 42 | _book 43 | _jsdoc 44 | 45 | # temp files 46 | *.log 47 | npm-debug.log* 48 | yarn-debug.log* 49 | yarn-error.log* 50 | bundle*.js 51 | book.pdf 52 | 53 | 54 | # ------------------------------- intellij ------------------------------- 55 | .idea 56 | *.iml 57 | 58 | 59 | # ------------------------------- eclipse ------------------------------- 60 | .classpath 61 | .project 62 | -------------------------------------------------------------------------------- /assets/Nginx.eddx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/assets/Nginx.eddx -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Nginx 教程 2 | 3 | > 🔁 项目同步维护在 [github](https://github.com/dunwu/nginx-tutorial) | [gitee](https://gitee.com/turnon/nginx-tutorial) 4 | > 5 | > 📖 [电子书](https://dunwu.github.io/nginx-tutorial/) | [电子书(国内)](http://turnon.gitee.io/nginx-tutorial/) 6 | 7 | - [Nginx 快速教程](nginx-quickstart.md) 8 | - [Nginx 运维](nginx-ops.md) 9 | - [Nginx 配置](nginx-configuration.md) 10 | - [Nginx 问题](nginx-faq.md) 11 | -------------------------------------------------------------------------------- /docs/coverpage.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # nginx-tutorial 4 | 5 | > 📚 **nginx-tutorial** 是一个 Nginx 极简教程。 6 | 7 | [开始阅读](README.md) 8 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | nginx-tutorial 6 | 7 | 8 | 12 | 13 | 14 | 15 | 21 | 80 | 81 | 82 |
正在加载...
83 | 84 | 85 | 86 | 87 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/nginx-faq.md: -------------------------------------------------------------------------------- 1 | # Nginx 问题集 2 | 3 | ## Nginx 出现大量 TIME_WAIT 4 | 5 | ### 检测TIME_WAIT状态的语句 6 | 7 | ```bash 8 | $ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 9 | SYN_RECV 7 10 | ESTABLISHED 756 11 | FIN_WAIT1 21 12 | SYN_SENT 3 13 | TIME_WAIT 2000 14 | ``` 15 | 16 | 状态解析: 17 | 18 | - `CLOSED` - 无连接是活动的或正在进行 19 | - `LISTEN` - 服务器在等待进入呼叫 20 | - `SYN_RECV` - 一个连接请求已经到达,等待确认 21 | - `SYN_SENT` - 应用已经开始,打开一个连接 22 | - `ESTABLISHED` - 正常数据传输状态 23 | - `FIN_WAIT1` - 应用说它已经完成 24 | - `FIN_WAIT2` - 另一边已同意释放 25 | - `ITMED_WAIT` - 等待所有分组死掉 26 | - `CLOSING` - 两边同时尝试关闭 27 | - `TIME_WAIT` - 另一边已初始化一个释放 28 | - `LAST_ACK` - 等待所有分组死掉 29 | 30 | ### 解决方法 31 | 32 | 执行 `vim /etc/sysctl.conf`,并添加下面字段 33 | 34 | ```properties 35 | net.ipv4.tcp_syncookies = 1 36 | net.ipv4.tcp_tw_reuse = 1 37 | net.ipv4.tcp_tw_recycle = 1 38 | net.ipv4.tcp_fin_timeout = 30 39 | ``` 40 | 41 | 执行 /`sbin/sysctl -p` 让修改生效。 42 | 43 | ## 上传文件大小限制 44 | 45 | ### 问题现象 46 | 47 | 显示错误信息:**413 Request Entity Too Large**。 48 | 49 | 意思是请求的内容过大,浏览器不能正确显示。常见的情况是发送 `POST` 请求来上传大文件。 50 | 51 | ### 解决方法 52 | 53 | - 可以在 `http` 模块中设置:`client_max_body_size 20m;` 54 | - 可以在 `server` 模块中设置:`client_max_body_size 20m;` 55 | - 可以在 `location` 模块中设置:`client_max_body_size 20m;` 56 | 57 | 三者区别是: 58 | 59 | - 如果文大小限制设置在 `http` 模块中,则对所有 Nginx 收到的请求。 60 | - 如果文大小限制设置在 `server` 模块中,则只对该 `server` 收到的请求生效。 61 | - 如果文大小限制设置在 `location` 模块中,则只对匹配了 `location` 路由规则的请求生效。 62 | 63 | ## 请求时间限制 64 | 65 | ### 问题现象 66 | 67 | 请求时间较长,链接被重置页面刷新。常见的情况是:上传、下载大文件。 68 | 69 | ### 解决方法 70 | 71 | 修改超时时间 72 | 73 | -------------------------------------------------------------------------------- /docs/nginx-introduction.md: -------------------------------------------------------------------------------- 1 | # Nginx 简介 2 | 3 | ## Ngnix 特点 4 | 5 | - 模块化设计:良好的扩展性,可以通过模块方式进行功能扩展。 6 | - 高可靠性:主控进程和 worker 是同步实现的,一个 worker 出现问题,会立刻启动另一个 worker。 7 | - 内存消耗低:一万个长连接(keep-alive),仅消耗 2.5MB 内存。 8 | - 支持热部署:不用停止服务器,实现更新配置文件,更换日志文件、更新服务器程序版本。 9 | - 并发能力强:官方数据每秒支持 5 万并发; 10 | - 功能丰富:优秀的反向代理功能和灵活的负载均衡策略 11 | 12 | ## Nginx 功能 13 | 14 | - 支持静态资源的 web 服务器。 15 | - http,smtp,pop3 协议的反向代理服务器、缓存、负载均衡; 16 | - 支持 FASTCGI(fpm) 17 | - 支持模块化,过滤器(让文本可以实现压缩,节约带宽),ssl 及图像大小调整。 18 | - 内置的健康检查功能 19 | - 基于名称和 ip 的虚拟主机 20 | - 定制访问日志 21 | - 支持平滑升级 22 | - 支持 KEEPALIVE 23 | - 支持 url rewrite 24 | - 支持路径别名 25 | - 支持基于 IP 和用户名的访问控制。 26 | - 支持传输速率限制,支持并发数限制。 27 | 28 | ## Nginx 性能 29 | 30 | Nginx 的高并发,官方测试支持 5 万并发连接。实际生产环境能到 2-3 万并发连接数。10000 个非活跃的 HTTP keep-alive 连接仅占用约 2.5MB 内存。三万并发连接下,10 个 Nginx 进程,消耗内存 150M。淘宝 tengine 团队测试结果是“24G 内存机器上,处理并发请求可达 200 万”。 31 | 32 | ## Ngnix 架构 33 | 34 | ### 主从模式 35 | 36 | ![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200125161055.png) 37 | 38 | **Nginx 采用一主多从的主从架构**。 39 | 40 | 但是这里 master 是使用 root 身份启动的,因为 nginx 要工作在 80 端口。而只有管理员才有权限启动小于低于 1023 的端口。master 主要是负责的作用只是启动 worker,加载配置文件,负责系统的平滑升级。其它的工作是交给 worker。那么当 worker 被启动之后,也只是负责一些 web 最简单的工作,而其他的工作都是有 worker 中调用的模块来实现的。 41 | 42 | 模块之间是以流水线的方式实现功能的。流水线,指的是一个用户请求,由多个模块组合各自的功能依次实现完成的。比如:第一个模块只负责分析请求首部,第二个模块只负责查找数据,第三个模块只负责压缩数据,依次完成各自工作。来实现整个工作的完成。 43 | 44 | 他们是如何实现热部署的呢?其实是这样的,我们前面说 master 不负责具体的工作,而是调用 worker 工作,他只是负责读取配置文件,因此当一个模块修改或者配置文件发生变化,是由 master 进行读取,因此此时不会影响到 worker 工作。在 master 进行读取配置文件之后,不会立即的把修改的配置文件告知 worker。而是让被修改的 worker 继续使用老的配置文件工作,当 worker 工作完毕之后,直接当掉这个子进程,更换新的子进程,使用新的规则。 45 | 46 | ### sendfile 机制 47 | 48 | **Nginx 支持 sendfile 机制**。 49 | 50 | 所谓 Sendfile 机制,是指:用户将请求发给内核,内核根据用户的请求调用相应用户进程,进程在处理时需要资源。此时再把请求发给内核(进程没有直接 IO 的能力),由内核加载数据。内核查找到数据之后,会把数据复制给用户进程,由用户进程对数据进行封装,之后交给内核,内核在进行 tcp/ip 首部的封装,最后再发给客户端。这个功能用户进程只是发生了一个封装报文的过程,却要绕一大圈。因此 nginx 引入了 sendfile 机制,使得内核在接受到数据之后,不再依靠用户进程给予封装,而是自己查找自己封装,减少了一个很长一段时间的浪费,这是一个提升性能的核心点。 51 | 52 |
53 | 54 | 以上内容摘自网友发布的文章,简单一句话是资源的处理,直接通过内核层进行数据传递,避免了数据传递到应用层,应用层再传递到内核层的开销。 55 | 56 | 目前高并发的处理,一般都采用 sendfile 模式。通过直接操作内核层数据,减少应用与内核层数据传递。 57 | 58 | ### I/O 复用机制 59 | 60 | **Nginx 通信模型采用 I/O 复用机制**。 61 | 62 | 开发模型:epoll 和 kqueue。 63 | 64 | 支持的事件机制:kqueue、epoll、rt signals、/dev/poll 、event ports、select 以及 poll。 65 | 66 | 支持的 kqueue 特性包括 EV_CLEAR、EV_DISABLE、NOTE_LOWAT、EV_EOF,可用数据的数量,错误代码. 67 | 68 | 支持 sendfile、sendfile64 和 sendfilev;文件 AIO;DIRECTIO;支持 Accept-filters 和 TCP_DEFER_ACCEP. 69 | 70 | 以上概念较多,大家自行百度或谷歌,知识领域是网络通信(BIO,NIO,AIO)和多线程方面的知识。 71 | 72 | ## Nginx 负载均衡 73 | 74 | nginx 的负载均衡策略可以划分为两大类:内置策略和扩展策略。内置策略包含加权轮询和 ip hash,在默认情况下这两种策略会编译进 nginx 内核,只需在 nginx 配置中指明参数即可。扩展策略有很多,如 fair、通用 hash、consistent hash 等,默认不编译进 nginx 内核。由于在 nginx 版本升级中负载均衡的代码没有本质性的变化,因此下面将以 nginx1.0.15 稳定版为例,从源码角度分析各个策略。 75 | 76 | ### 加权轮询 77 | 78 | **Nginx 支持加权轮询(Weighted Round Robin)负载均衡**。 79 | 80 | 轮询的原理很简单,首先我们介绍一下轮询的基本流程。如下是处理一次请求的流程图: 81 | 82 |
83 | 84 | 图中有两点需要注意,第一,如果可以把加权轮询算法分为先深搜索和先广搜索,那么 nginx 采用的是先深搜索算法,即将首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器;第二,当所有后端机器都 down 掉时,nginx 会立即将所有机器的标志位清成初始状态,以避免造成所有的机器都处在 timeout 的状态,从而导致整个前端被夯住。 85 | 86 | ### Ip Hash 87 | 88 | **Nginx 支持 Ip Hash 负载均衡**。 89 | 90 | 通过 Ip Hash 这种负载均衡策略,可以实现会话粘滞。 91 | 92 | ### Fair 93 | 94 | fair 策略是扩展策略,默认不被编译进 nginx 内核。其原理是根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进行分流。这种策略具有很强的自适应性,但是实际的网络环境往往不是那么简单,因此要慎用。 95 | 96 | ### 通用 Hash、一致性 Hash 97 | 98 | 这两种也是扩展策略,在具体的实现上有些差别,通用 hash 比较简单,可以以 nginx 内置的变量为 key 进行 hash,一致性 hash 采用了 nginx 内置的一致性 hash 环,可以支持 memcache。 99 | 100 | ## Nginx 场景 101 | 102 | Ngnix 一般作为入口负载均衡或内部负载均衡,结合反向代理服务器使用。以下架构示例,仅供参考,具体使用根据场景而定。 103 | 104 | ### 入口负载均衡架构 105 | 106 |
107 | 108 | Ngnix 服务器在用户访问的最前端。根据用户请求再转发到具体的应用服务器或二级负载均衡服务器(LVS) 109 | 110 | ### 内部负载均衡架构 111 | 112 |
113 | 114 | LVS 作为入口负载均衡,将请求转发到二级 Ngnix 服务器,Ngnix 再根据请求转发到具体的应用服务器。 115 | 116 | ### Ngnix 高可用 117 | 118 |
119 | 120 | 分布式系统中,应用只部署一台服务器会存在单点故障,负载均衡同样有类似的问题。一般可采用主备或负载均衡设备集群的方式节约单点故障或高并发请求分流。 121 | 122 | Ngnix 高可用,至少包含两个 Ngnix 服务器,一台主服务器,一台备服务器,之间使用 Keepalived 做健康监控和故障检测。开放 VIP 端口,通过防火墙进行外部映射。 123 | 124 | DNS 解析公网的 IP 实际为 VIP。 125 | -------------------------------------------------------------------------------- /docs/nginx-ops.md: -------------------------------------------------------------------------------- 1 | # Nginx 运维 2 | 3 | 4 | 5 | - [Windows 安装](#windows-安装) 6 | - [Linux 安装](#linux-安装) 7 | - [rpm 包方式(推荐)](#rpm-包方式推荐) 8 | - [源码编译方式](#源码编译方式) 9 | - [Linux 开机自启动](#linux-开机自启动) 10 | - [rpm 包方式](#rpm-包方式) 11 | - [源码编译方式](#源码编译方式-1) 12 | - [脚本](#脚本) 13 | - [参考资料](#参考资料) 14 | 15 | 16 | 17 | ## 一、普通安装 18 | 19 | ### Windows 安装 20 | 21 | (1)进入[官方下载地址](https://nginx.org/en/download.html),选择合适版本(nginx/Windows-xxx)。 22 | 23 | ![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20180920181023092347.png) 24 | 25 | (2)解压到本地 26 | 27 | ![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20180920181023092044.png) 28 | 29 | (3)启动 30 | 31 | 下面以 C 盘根目录为例说明下: 32 | 33 | ```bash 34 | cd C: 35 | cd C:\nginx-0.8.54 start nginx 36 | ``` 37 | 38 | > 注:Nginx / Win32 是运行在一个控制台程序,而非 windows 服务方式的。服务器方式目前还是开发尝试中。 39 | 40 | ### Linux 安装 41 | 42 | #### rpm 包方式(推荐) 43 | 44 | (1)进入[下载页面](http://nginx.org/packages/),选择合适版本下载。 45 | 46 | ```bash 47 | $ wget http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm 48 | ``` 49 | 50 | (2)安装 nginx rpm 包 51 | 52 | nginx rpm 包实际上安装的是 nginx 的 yum 源。 53 | 54 | ```bash 55 | $ rpm -ivh nginx-*.rpm 56 | ``` 57 | 58 | (3)正式安装 rpm 包 59 | 60 | ```bash 61 | $ yum install nginx 62 | ``` 63 | 64 | (4)关闭防火墙 65 | 66 | ```bash 67 | $ firewall-cmd --zone=public --add-port=80/tcp --permanent 68 | $ firewall-cmd --reload 69 | ``` 70 | 71 | #### 源码编译方式 72 | 73 | ##### 安装编译工具及库 74 | 75 | Nginx 源码的编译依赖于 gcc 以及一些库文件,所以必须提前安装。 76 | 77 | ```bash 78 | $ yum -y install make zlib zlib-devel gcc-c++ libtool openssl openssl-devel 79 | ``` 80 | 81 | Nginx 依赖 pcre 库,安装步骤如下: 82 | 83 | (1)下载解压到本地 84 | 85 | 进入[pcre 官网下载页面](https://sourceforge.net/projects/pcre/files/pcre/),选择合适的版本下载。 86 | 87 | 我选择的是 8.35 版本: 88 | 89 | ```bash 90 | wget -O /opt/pcre/pcre-8.35.tar.gz http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz 91 | cd /opt/pcre 92 | tar zxvf pcre-8.35.tar.gz 93 | ``` 94 | 95 | (2)编译安装 96 | 97 | 执行以下命令: 98 | 99 | ```bash 100 | cd /opt/pcre/pcre-8.35 101 | ./configure 102 | make && make install 103 | ``` 104 | 105 | (3)检验是否安装成功 106 | 107 | 执行 `pcre-config --version` 命令。 108 | 109 | ##### 编译安装 Nginx 110 | 111 | 安装步骤如下: 112 | 113 | (1)下载解压到本地 114 | 115 | 进入官网下载地址:http://nginx.org/en/download.html ,选择合适的版本下载。 116 | 117 | 我选择的是 1.12.2 版本:http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz 118 | 119 | ```bash 120 | wget -O /opt/nginx/nginx-1.12.2.tar.gz http://nginx.org/download/nginx-1.12.2.tar.gz 121 | cd /opt/nginx 122 | tar zxvf nginx-1.12.2.tar.gz 123 | ``` 124 | 125 | (2)编译安装 126 | 127 | 执行以下命令: 128 | 129 | ```bash 130 | cd /opt/nginx/nginx-1.12.2 131 | ./configure --with-http_stub_status_module --with-http_ssl_module --with-pcre=/opt/pcre/pcre-8.35 132 | make && make install 133 | ``` 134 | 135 | (3)关闭防火墙 136 | 137 | ```bash 138 | $ firewall-cmd --zone=public --add-port=80/tcp --permanent 139 | $ firewall-cmd --reload 140 | ``` 141 | 142 | (4) 启动 Nginx 143 | 144 | 安装成功后,直接执行 `nginx` 命令即可启动 nginx。 145 | 146 | 启动后,访问站点: 147 | 148 | ![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20180920181016133223.png) 149 | 150 | #### Linux 开机自启动 151 | 152 | Centos7 以上是用 Systemd 进行系统初始化的,Systemd 是 Linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度。Systemd 服务文件以 .service 结尾。 153 | 154 | ##### rpm 包方式 155 | 156 | 如果是通过 rpm 包安装的,会自动创建 nginx.service 文件。 157 | 158 | 直接用命令: 159 | 160 | ```bash 161 | $ systemctl enable nginx.service 162 | ``` 163 | 164 | 设置开机启动即可。 165 | 166 | ##### 源码编译方式 167 | 168 | 如果采用源码编译方式,需要手动创建 nginx.service 文件。 169 | 170 | ## 二、Docker 安装 171 | 172 | - 官网镜像:https://hub.docker.com/_/nginx/ 173 | - 下载镜像:`docker pull nginx` 174 | - 启动容器:`docker run --name my-nginx -p 80:80 -v /data/docker/nginx/logs:/var/log/nginx -v /data/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx` 175 | - 重新加载配置(目前测试无效,只能重启服务):`docker exec -it my-nginx nginx -s reload` 176 | - 停止服务:`docker exec -it my-nginx nginx -s stop` 或者:`docker stop my-nginx` 177 | - 重新启动服务:`docker restart my-nginx` 178 | 179 | ## 三、脚本 180 | 181 | > CentOS7 环境安装脚本:[软件运维配置脚本集合](https://github.com/dunwu/linux-tutorial/tree/master/codes/linux/soft) 182 | 183 | **安装说明** 184 | 185 | - 采用编译方式安装 Nginx, 并将其注册为 systemd 服务 186 | - 安装路径为:`/usr/local/nginx` 187 | - 默认下载安装 `1.16.0` 版本 188 | 189 | **使用方法** 190 | 191 | - 默认安装 - 执行以下任意命令即可: 192 | 193 | ```shell 194 | curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nginx-install.sh | bash 195 | wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/nginx-install.sh | bash 196 | ``` 197 | 198 | - 自定义安装 - 下载脚本到本地,并按照以下格式执行: 199 | 200 | ```bash 201 | sh nginx-install.sh [version] 202 | ``` 203 | 204 | ## 参考资料 205 | 206 | - http://www.dohooe.com/2016/03/03/352.html?utm_source=tuicool&utm_medium=referral 207 | - [nginx+keepalived实现nginx双主高可用的负载均衡](https://blog.51cto.com/kling/1253474) 208 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nginx-tutorial", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "start": "docsify serve ./ --port 4000" 6 | }, 7 | "dependencies": {}, 8 | "devDependencies": {} 9 | } 10 | -------------------------------------------------------------------------------- /docs/sidebar.md: -------------------------------------------------------------------------------- 1 | # nginx-tutorial 2 | 3 | - [Nginx 快速教程](nginx-quickstart.md) 4 | - [Nginx 运维](nginx-ops.md) 5 | - [Nginx 配置](nginx-configuration.md) 6 | - [Nginx 问题](nginx-faq.md) 7 | -------------------------------------------------------------------------------- /examples/images/nginx-demo01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/images/nginx-demo01.png -------------------------------------------------------------------------------- /examples/images/nginx-demo02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/images/nginx-demo02.png -------------------------------------------------------------------------------- /examples/images/nginx-demo03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/images/nginx-demo03.png -------------------------------------------------------------------------------- /examples/images/nginx-demo04(2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/images/nginx-demo04(2).png -------------------------------------------------------------------------------- /examples/images/nginx-demo04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/images/nginx-demo04.png -------------------------------------------------------------------------------- /examples/images/nginx-demo05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/images/nginx-demo05.png -------------------------------------------------------------------------------- /examples/images/nginx-demo06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/images/nginx-demo06.png -------------------------------------------------------------------------------- /examples/javaapp/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | io.github.dunwu 7 | JavaWebApp 8 | 1.0.0 9 | war 10 | ${project.artifactId} 11 | 12 | UTF-8 13 | 1.8 14 | ${java.version} 15 | ${java.version} 16 | 5.0.2.RELEASE 17 | 8.5.50 18 | 19 | 20 | 21 | 22 | javax.servlet 23 | javax.servlet-api 24 | 3.1.0 25 | 26 | 27 | javax.servlet.jsp 28 | jsp-api 29 | 2.2 30 | 31 | 32 | 33 | 34 | 35 | org.springframework 36 | spring-context-support 37 | 38 | 39 | org.springframework 40 | spring-webmvc 41 | 42 | 43 | 44 | 45 | 46 | org.apache.tomcat.embed 47 | tomcat-embed-core 48 | ${tomcat.version} 49 | 50 | 51 | org.apache.tomcat.embed 52 | tomcat-embed-jasper 53 | ${tomcat.version} 54 | 55 | 56 | 57 | 58 | org.apache.commons 59 | commons-lang3 60 | 3.7 61 | 62 | 63 | ch.qos.logback 64 | logback-classic 65 | 1.1.2 66 | 67 | 68 | com.fasterxml.jackson.core 69 | jackson-databind 70 | 2.9.10.1 71 | 72 | 73 | 74 | 75 | 76 | 77 | org.springframework 78 | spring-framework-bom 79 | ${spring.version} 80 | pom 81 | import 82 | 83 | 84 | 85 | 86 | 87 | ${project.artifactId} 88 | 89 | 90 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/Main.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu; 2 | 3 | import org.apache.catalina.Server; 4 | import org.apache.catalina.startup.Catalina; 5 | import org.apache.catalina.startup.Tomcat; 6 | import org.apache.tomcat.util.digester.Digester; 7 | import org.apache.tomcat.util.scan.Constants; 8 | 9 | import java.io.File; 10 | 11 | public class Main { 12 | 13 | private static final String CONNECTOR_PORT = "8080"; 14 | 15 | // 以下设置轻易不要改动 16 | private static final String RELATIVE_DEV_BASE_DIR = "src/main/resources/tomcat/"; 17 | 18 | private static final String RELATIVE_BASE_DIR = "WEB-INF/classes/tomcat/"; 19 | 20 | private static final String RELATIVE_DEV_DOCBASE_DIR = "src/main/webapp"; 21 | 22 | private static final String RELATIVE_DOCBASE_DIR = ""; 23 | 24 | private static final String CONTEXT_PATH = "/"; 25 | 26 | public static void main(String[] args) throws Exception { 27 | System.setProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow", "{}|"); 28 | 29 | System.setProperty("tomcat.host.appBase", getAbsolutePath()); 30 | File checkFile = new File(System.getProperty("tomcat.host.appBase") + "/WEB-INF"); 31 | if (!checkFile.exists()) { 32 | System.setProperty("catalina.base", getAbsolutePath() + RELATIVE_DEV_BASE_DIR); 33 | System.setProperty("tomcat.context.docBase", RELATIVE_DEV_DOCBASE_DIR); 34 | } else { 35 | System.setProperty("catalina.base", getAbsolutePath() + RELATIVE_BASE_DIR); 36 | System.setProperty("tomcat.context.docBase", RELATIVE_DOCBASE_DIR); 37 | } 38 | 39 | if (isBlank(System.getProperty("tomcat.connector.port"))) { 40 | System.setProperty("tomcat.connector.port", CONNECTOR_PORT); 41 | } 42 | if (isBlank(System.getProperty("tomcat.server.shutdownPort"))) { 43 | System.setProperty("tomcat.server.shutdownPort", 44 | String.valueOf(Integer.valueOf(System.getProperty("tomcat.connector.port")) + 10000)); 45 | } 46 | if (isBlank(System.getProperty("tomcat.context.path"))) { 47 | System.setProperty("tomcat.context.path", CONTEXT_PATH); 48 | } 49 | 50 | System.out.println("====================ENV setting===================="); 51 | System.out.println("spring.profiles.active:" + System.getProperty("spring.profiles.active")); 52 | System.out.println("catalina.base:" + System.getProperty("catalina.base")); 53 | System.out.println("tomcat.host.appBase:" + System.getProperty("tomcat.host.appBase")); 54 | System.out.println("tomcat.context.docBase:" + System.getProperty("tomcat.context.docBase")); 55 | System.out.println("tomcat.context.path:" + System.getProperty("tomcat.context.path")); 56 | System.out.println("tomcat.connector.port:" + System.getProperty("tomcat.connector.port")); 57 | System.out.println("tomcat.server.shutdownPort:" + System.getProperty("tomcat.server.shutdownPort")); 58 | 59 | ExtendedTomcat tomcat = new ExtendedTomcat(); 60 | tomcat.start(); 61 | tomcat.getServer().await(); 62 | } 63 | 64 | private static String getAbsolutePath() { 65 | String path = null; 66 | String folderPath = Main.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 67 | if (folderPath.indexOf("WEB-INF") > 0) { 68 | path = folderPath.substring(0, folderPath.indexOf("WEB-INF")); 69 | } else if (folderPath.indexOf("target") > 0) { 70 | path = folderPath.substring(0, folderPath.indexOf("target")); 71 | } 72 | return path; 73 | } 74 | 75 | private static boolean isBlank(String str) { 76 | if (str == null || str.isEmpty()) { 77 | return true; 78 | } 79 | return false; 80 | } 81 | 82 | static class ExtendedTomcat extends Tomcat { 83 | 84 | private static final String RELATIVE_SERVERXML_PATH = "/conf/server.xml"; 85 | 86 | @Override 87 | public Server getServer() { 88 | if (server != null) { 89 | return server; 90 | } 91 | // 默认不开启JNDI. 开启时, 注意maven必须添加tomcat-dbcp依赖 92 | System.setProperty("catalina.useNaming", "false"); 93 | ExtendedCatalina extendedCatalina = new ExtendedCatalina(); 94 | 95 | // 覆盖默认的skip和scan jar包配置 96 | System.setProperty(Constants.SKIP_JARS_PROPERTY, ""); 97 | System.setProperty(Constants.SCAN_JARS_PROPERTY, ""); 98 | 99 | Digester digester = extendedCatalina.createStartDigester(); 100 | digester.push(extendedCatalina); 101 | try { 102 | server = ((ExtendedCatalina) digester.parse( 103 | new File(System.getProperty("catalina.base") + RELATIVE_SERVERXML_PATH))).getServer(); 104 | // 设置catalina.base和catalna.home 105 | this.initBaseDir(); 106 | return server; 107 | } catch (Exception e) { 108 | System.err.println("Error while parsing server.xml" + e.getMessage()); 109 | throw new RuntimeException( 110 | "server未创建,请检查server.xml(路径:" + System.getProperty("catalina.base") + RELATIVE_SERVERXML_PATH 111 | + ")配置是否正确"); 112 | } 113 | } 114 | 115 | 116 | private class ExtendedCatalina extends Catalina { 117 | 118 | @Override 119 | public Digester createStartDigester() { 120 | return super.createStartDigester(); 121 | } 122 | 123 | } 124 | 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/filter/CorsFilter.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.filter; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.*; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | import java.util.regex.Pattern; 12 | 13 | /** 14 | * 跨域过滤器,根据正则进行匹配 15 | */ 16 | public class CorsFilter implements Filter { 17 | 18 | private static final Logger logger = LoggerFactory.getLogger(CorsFilter.class); 19 | 20 | private final String ORIGIN_KEY = "Origin"; 21 | 22 | private String regex; 23 | 24 | private String headerKey; 25 | 26 | private String protocol = "http"; 27 | 28 | public void init(FilterConfig filterConfig) { 29 | // 取配置参数 30 | regex = filterConfig.getInitParameter("regex"); 31 | headerKey = filterConfig.getInitParameter("headerKey"); 32 | String protocolVal = filterConfig.getInitParameter("protocol"); 33 | if (StringUtils.isNotBlank(protocolVal)) { 34 | if (StringUtils.equalsIgnoreCase("http", protocolVal) || StringUtils.equalsIgnoreCase("https", 35 | protocolVal)) { 36 | protocol = protocolVal.toLowerCase(); 37 | } else { 38 | logger.error("CorsFilter 配置参数 protocol 非法,仍使用默认值 http"); 39 | } 40 | } 41 | } 42 | 43 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 44 | throws IOException, ServletException { 45 | HttpServletRequest httpRequest = (HttpServletRequest) request; 46 | HttpServletResponse httpResponse = (HttpServletResponse) response; 47 | 48 | if (StringUtils.isBlank(regex) || StringUtils.isBlank(headerKey)) { 49 | throw new ServletException("读取跨域过滤器的配置参数失败"); 50 | } 51 | 52 | // 读取请求地址的域 53 | String domain = httpRequest.getHeader(headerKey); 54 | String origin = httpRequest.getHeader(ORIGIN_KEY); 55 | 56 | if (StringUtils.isBlank(origin)) { 57 | logger.debug("origin 为空, 跳过检查"); 58 | chain.doFilter(httpRequest, httpResponse); 59 | return; 60 | } 61 | 62 | if (StringUtils.isBlank(domain)) { 63 | logger.debug("domain 为空, 跳过检查"); 64 | chain.doFilter(httpRequest, httpResponse); 65 | return; 66 | } 67 | 68 | if (origin.toLowerCase().contains(domain.toLowerCase())) { 69 | // 判断请求方和应答方是否同为 http 或 https 70 | // 如果相同,这里视为同源;否则,视为跨域 71 | if (origin.startsWith(protocol)) { 72 | logger.debug("domain={}, origin={}, 二者协议相同,且域名同源,跳过检查", domain, origin); 73 | chain.doFilter(httpRequest, httpResponse); 74 | return; 75 | } 76 | } 77 | 78 | Pattern pattern = Pattern.compile(regex); 79 | if (!pattern.matcher(origin).matches()) { 80 | logger.warn("客户端域 origin={} 不在跨域白名单中", origin); 81 | httpResponse.sendError(403, "客户端域不在跨域白名单中"); 82 | throw new ServletException("客户端域不在跨域白名单中"); 83 | } 84 | 85 | logger.debug("对 origin={} 放开跨域限制", origin); 86 | httpResponse.addHeader("Access-Control-Allow-Origin", origin); 87 | httpResponse.addHeader("Access-Control-Allow-Credentials", "true"); 88 | httpResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, DELETE"); 89 | httpResponse.addHeader("Access-Control-Allow-Headers", 90 | "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since," 91 | + " Cache-Control, Content-Type, Content-Range, Range, X-CSRF-TOKEN"); 92 | httpResponse.addHeader("Access-Control-Expose-Headers", 93 | "DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since," 94 | + " Cache-Control, Content-Type, Content-Range, Range"); 95 | if (httpRequest.getMethod().equals("OPTIONS")) { 96 | httpResponse.setStatus(HttpServletResponse.SC_OK); 97 | return; 98 | } 99 | chain.doFilter(httpRequest, httpResponse); 100 | } 101 | 102 | public void destroy() { 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/util/IOObjectMapper.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 4 | import com.fasterxml.jackson.databind.DeserializationFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | 7 | public class IOObjectMapper extends ObjectMapper { 8 | 9 | public IOObjectMapper() { 10 | this.setSerializationInclusion(Include.NON_EMPTY); 11 | this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/web/controller/ApiController.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.web.controller; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import io.github.dunwu.web.dto.BaseResponseDTO; 6 | import io.github.dunwu.web.dto.MenuDTO; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.ResponseBody; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | import java.io.IOException; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.Set; 19 | import java.util.TreeSet; 20 | 21 | /** 22 | * 配合前端请求的 API 接口 23 | * 24 | * @author zhangpeng0913 25 | * @since 2017/8/23. 26 | */ 27 | @Controller 28 | public class ApiController { 29 | 30 | private static Set getAll() { 31 | MenuDTO item0 = new MenuDTO("0", "首页", "home", "Item", "/pages/home"); 32 | 33 | MenuDTO subMenu1 = new MenuDTO("1", "业务", "bars", "SubMenu", null); 34 | MenuDTO item11 = new MenuDTO("11", "Mailbox", "mail", "Item", "/pages/mailbox"); 35 | MenuDTO item12 = new MenuDTO("12", "用户列表", "user", "Item", "/pages/user"); 36 | subMenu1.addChild(item11); 37 | subMenu1.addChild(item12); 38 | 39 | MenuDTO subMenu2 = new MenuDTO("2", "Others", "coffee", "SubMenu", null); 40 | MenuDTO itemGroup1 = new MenuDTO("21", "Group1", "windows-o", "ItemGroup", null); 41 | MenuDTO item22 = new MenuDTO("22", "Group1-1", null, "Item", null); 42 | MenuDTO divider = new MenuDTO("23", "Divider1", null, "Divider", null); 43 | MenuDTO itemGroup2 = new MenuDTO("24", "Group2", "apple-o", "ItemGroup", null); 44 | MenuDTO item25 = new MenuDTO("25", "Group2-1", null, "Item", null); 45 | itemGroup1.addChild(item22); 46 | itemGroup2.addChild(item25); 47 | subMenu2.addChild(itemGroup1); 48 | subMenu2.addChild(divider); 49 | subMenu2.addChild(itemGroup2); 50 | 51 | Set menus = new TreeSet(); 52 | menus.add(item0); 53 | menus.add(subMenu1); 54 | menus.add(subMenu2); 55 | 56 | return menus; 57 | } 58 | 59 | @ResponseBody 60 | @RequestMapping(value = "/menu", method = RequestMethod.GET) 61 | public BaseResponseDTO getAll(HttpServletRequest request) throws JsonProcessingException { 62 | String data = request.getParameter("data"); 63 | BaseResponseDTO baseResponseDTO = new BaseResponseDTO(); 64 | baseResponseDTO.setData(getAll()); 65 | ObjectMapper om = new ObjectMapper(); 66 | System.out.println("ResponseDTO: " + om.writeValueAsString(baseResponseDTO)); 67 | return baseResponseDTO; 68 | } 69 | 70 | @ResponseBody 71 | @RequestMapping(value = "/login") 72 | public BaseResponseDTO login(@RequestBody Map map) throws IOException { 73 | String username = map.get("username"); 74 | String password = map.get("password"); 75 | BaseResponseDTO> baseResponseDTO = new BaseResponseDTO(); 76 | if (StringUtils.equals(username, "admin") && StringUtils.equals(password, "123456")) { 77 | Map result = new HashMap(); 78 | result.put("name", "admin"); 79 | result.put("role", "ADMIN"); 80 | result.put("uid", "1"); 81 | baseResponseDTO.setData(result); 82 | System.out.println(baseResponseDTO.toString()); 83 | return baseResponseDTO; 84 | } else { 85 | baseResponseDTO.setCode(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.value()); 86 | baseResponseDTO.getMessages().add(BaseResponseDTO.DEFAULT_RESPONSE_RESULT.SYSTEM_ERROR.desc()); 87 | return baseResponseDTO; 88 | } 89 | } 90 | 91 | @ResponseBody 92 | @RequestMapping(value = "/logout", method = RequestMethod.GET) 93 | public BaseResponseDTO logout(HttpServletRequest request) { 94 | BaseResponseDTO baseResponseDTO = new BaseResponseDTO(); 95 | return baseResponseDTO; 96 | } 97 | 98 | @ResponseBody 99 | @RequestMapping(value = "/my", method = RequestMethod.GET) 100 | public BaseResponseDTO my(HttpServletRequest request) { 101 | Map map = new HashMap(); 102 | map.put("name", "admin"); 103 | map.put("role", "ADMIN"); 104 | map.put("uid", "1"); 105 | BaseResponseDTO baseResponseDTO = new BaseResponseDTO(); 106 | baseResponseDTO.setData(map); 107 | return baseResponseDTO; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/web/controller/HelloController.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.web.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestMethod; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.servlet.ModelAndView; 8 | 9 | /** 10 | * spring mvc 的第一个程序 11 | * 12 | * @author Zhang Peng 13 | * @since 2016.07.29 14 | */ 15 | @Controller 16 | @RequestMapping(value = "/hello") 17 | public class HelloController { 18 | 19 | /** 20 | *

21 | * 在本例中,Spring将会将数据传给 hello.jsp 22 | *

23 | * 访问形式:http://localhost:8080/hello?name=张三 24 | */ 25 | @RequestMapping(value = "/name", method = RequestMethod.GET) 26 | public ModelAndView hello(@RequestParam("name") String name) { 27 | ModelAndView mav = new ModelAndView(); 28 | mav.addObject("message", "你好," + name); 29 | mav.setViewName("hello"); 30 | return mav; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/web/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The Apache License 2.0 Copyright (c) 2016 Zhang Peng 3 | */ 4 | package io.github.dunwu.web.controller; 5 | 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | /** 12 | * @author Zhang Peng 13 | * @since 2017/4/12. 14 | */ 15 | @Controller 16 | public class IndexController { 17 | 18 | /** 19 | *

20 | * 返回 ModelAndView 对象到视图层。在本例中,视图解析器解析视图名为 index,会自动关联到 index.jsp。 21 | *

22 | * 访问形式:http://localhost:8080/ 23 | */ 24 | @RequestMapping(value = "/", method = RequestMethod.GET) 25 | public ModelAndView index() { 26 | ModelAndView mav = new ModelAndView(); 27 | mav.setViewName("index"); 28 | return mav; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/web/dto/BaseResponseDTO.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.web.dto; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | public class BaseResponseDTO { 8 | 9 | private final List messages = new ArrayList<>(); 10 | 11 | private Integer code = DEFAULT_RESPONSE_RESULT.SUCCESS.value(); 12 | 13 | private T data; 14 | 15 | public BaseResponseDTO() { 16 | } 17 | 18 | public BaseResponseDTO(T dto) { 19 | this.data = dto; 20 | } 21 | 22 | public Integer getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(Integer code) { 27 | this.code = code; 28 | } 29 | 30 | public void addError(String error) { 31 | this.messages.add(error); 32 | } 33 | 34 | public void addErrors(String[] errors) { 35 | this.addErrors(Arrays.asList(errors)); 36 | } 37 | 38 | public void addErrors(List errorList) { 39 | this.messages.addAll(errorList); 40 | } 41 | 42 | public void removeError(String error) { 43 | this.messages.remove(error); 44 | } 45 | 46 | public List getMessages() { 47 | return messages; 48 | } 49 | 50 | public T getData() { 51 | return data; 52 | } 53 | 54 | public void setData(T data) { 55 | this.data = data; 56 | } 57 | 58 | public enum DEFAULT_RESPONSE_RESULT { 59 | 60 | SUCCESS(0, "[]"), // 成功 61 | AUTHEN_FAIL(-1, "认证失败"), // 认证失败 62 | AUTHOR_FAIL(-2, "权限不足"), // 授权不足 63 | PARAM_CHECK_FAIL(-3, ""), // 参数校验失败,错误信息交由业务逻辑处理 64 | RESOURCE_NOT_EXIST(-4, "请求资源不存在"), // 请求资源不存在 65 | SYSTEM_ERROR(-5, "系统错误"), 66 | DATA_MALFORMAT(-6, "请求参数数据格式不正确"), 67 | REQMETHOD_ERROR(-7, "请求方法不正确"), 68 | TYPE_MISMATCH(-8, "请求参数类型不匹配"), 69 | MISS_REQUEST_PARAM(-9, "请求参数缺失"); 70 | 71 | private final Integer value; 72 | 73 | private final String desc; 74 | 75 | DEFAULT_RESPONSE_RESULT(int value, String desc) { 76 | this.value = value; 77 | this.desc = desc; 78 | } 79 | 80 | public int value() { 81 | return value; 82 | } 83 | 84 | public String desc() { 85 | return desc; 86 | } 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/java/io/github/dunwu/web/dto/MenuDTO.java: -------------------------------------------------------------------------------- 1 | package io.github.dunwu.web.dto; 2 | 3 | import org.apache.commons.lang3.builder.CompareToBuilder; 4 | import org.apache.commons.lang3.builder.EqualsBuilder; 5 | import org.apache.commons.lang3.builder.HashCodeBuilder; 6 | 7 | import java.util.Arrays; 8 | import java.util.Set; 9 | import java.util.TreeSet; 10 | 11 | public class MenuDTO implements Cloneable, Comparable { 12 | 13 | private final Set children = new TreeSet(); 14 | 15 | private String key; 16 | 17 | private String title; 18 | 19 | private String icon; 20 | 21 | private String type; 22 | 23 | private String url; 24 | 25 | public MenuDTO() { 26 | } 27 | 28 | public MenuDTO(String key, String title, String icon, String type, String url) { 29 | this.key = key; 30 | this.title = title; 31 | this.icon = icon; 32 | this.type = type; 33 | this.url = url; 34 | } 35 | 36 | public MenuDTO clone() throws CloneNotSupportedException { 37 | super.clone(); 38 | MenuDTO menuDTO = new MenuDTO(); 39 | menuDTO.setType(type); 40 | menuDTO.setKey(key); 41 | menuDTO.setTitle(title); 42 | menuDTO.setIcon(icon); 43 | menuDTO.setUrl(url); 44 | menuDTO.setUrl(url); 45 | return menuDTO; 46 | } 47 | 48 | public String getKey() { 49 | return key; 50 | } 51 | 52 | public void setKey(String key) { 53 | this.key = key; 54 | } 55 | 56 | public String getTitle() { 57 | return title; 58 | } 59 | 60 | public void setTitle(String title) { 61 | this.title = title; 62 | } 63 | 64 | public String getIcon() { 65 | return icon; 66 | } 67 | 68 | public void setIcon(String icon) { 69 | this.icon = icon; 70 | } 71 | 72 | public String getType() { 73 | return type; 74 | } 75 | 76 | public void setType(String type) { 77 | this.type = type; 78 | } 79 | 80 | public String getUrl() { 81 | return url; 82 | } 83 | 84 | public void setUrl(String url) { 85 | this.url = url; 86 | } 87 | 88 | public Set getChildren() { 89 | return children; 90 | } 91 | 92 | public void addChild(MenuDTO child) { 93 | this.children.add(child); 94 | } 95 | 96 | public void addChildren(Set children) { 97 | this.children.addAll(children); 98 | } 99 | 100 | public void addChildren(MenuDTO[] children) { 101 | this.children.addAll(Arrays.asList(children)); 102 | } 103 | 104 | @Override 105 | public boolean equals(Object obj) { 106 | boolean equals = false; 107 | if (obj instanceof MenuDTO) { 108 | MenuDTO menuDTO = (MenuDTO) obj; 109 | equals = (new EqualsBuilder().append(url, menuDTO.getUrl())).isEquals(); 110 | } 111 | return equals; 112 | } 113 | 114 | @Override 115 | public int hashCode() { 116 | return new HashCodeBuilder(17, 37).append(url).toHashCode(); 117 | } 118 | 119 | @Override 120 | public int compareTo(MenuDTO otherMenuDTO) { 121 | return new CompareToBuilder().append(key, otherMenuDTO.getKey()) 122 | .append(url, otherMenuDTO.getUrl()) 123 | .toComparison(); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/resources/spring/spring-servlet.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/resources/tomcat/conf/server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 14 | 15 | 16 | 19 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/webapp/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: io.github.dunwu.Main 3 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | spring-embed-tomcat-demo-helloworld 5 | 6 | 7 | 8 | spring-servlet 9 | org.springframework.web.servlet.DispatcherServlet 10 | 1 11 | 12 | contextConfigLocation 13 | classpath:spring/spring-servlet.xml 14 | 15 | 16 | 17 | spring-servlet 18 | / 19 | 20 | 21 | 22 | 23 | 24 | 25 | encodingFilter 26 | org.springframework.web.filter.CharacterEncodingFilter 27 | 28 | encoding 29 | UTF-8 30 | 31 | 32 | forceEncoding 33 | true 34 | 35 | 36 | 37 | encodingFilter 38 | /* 39 | REQUEST 40 | FORWARD 41 | 42 | 43 | 44 | CorsFilter 45 | io.github.dunwu.filter.CorsFilter 46 | 47 | headerKey 48 | Host 49 | 50 | 51 | regex 52 | 53 | ((http://)|(https://))?(\w*\.)*(\S)* 54 | 55 | 56 | 57 | CorsFilter 58 | /* 59 | 60 | 61 | 62 | 63 | /views/jsp/index.jsp 64 | 65 | 66 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/webapp/views/jsp/hello.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> 2 | <% 3 | String path = request.getContextPath(); 4 | String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; 5 | %> 6 | 7 | 8 | 9 | 10 | HelloController 11 | 12 | 13 |

${message}

14 | 回到首页
15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/javaapp/src/main/webapp/views/jsp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> 2 | <% 3 | String domain = request.getScheme() + "://" + request.getServerName() + request.getContextPath(); 4 | String host = request.getRemoteHost(); 5 | // int port = request.getServerPort(); 6 | Integer port = Integer.valueOf(System.getProperty("tomcat.connector.port")); 7 | 8 | 9 | %> 10 | 11 | 12 | 13 | 14 | spring-embed-tomcat-demo 15 | 16 | 17 | 18 |

spring-embed-tomcat-demo

19 |

<%out.print("当前服务器信息:");%>

20 |
    21 |
  • <%out.print("domain:" + domain);%>
  • 22 |
  • <%out.print("host:" + host);%>
  • 23 |
  • <%out.print("port:" + port);%>
  • 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/conf.d/demo01.conf: -------------------------------------------------------------------------------- 1 | #------------------------------------------- 2 | # 简单的反向代理示例 3 | #------------------------------------------- 4 | 5 | upstream demo01_server { 6 | server 127.0.0.1:9010; 7 | } 8 | 9 | server { 10 | listen 80; 11 | server_name www.demo01.com; 12 | 13 | charset utf-8; 14 | proxy_connect_timeout 180; 15 | proxy_send_timeout 180; 16 | proxy_read_timeout 180; 17 | proxy_set_header Host $host; 18 | proxy_set_header X-Forwarded-For $remote_addr; 19 | 20 | # root /home/nginx/demos; 21 | root ../../../javaapp/src/main/webapp; 22 | 23 | location / { 24 | proxy_pass http://demo01_server; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/conf.d/demo02.conf: -------------------------------------------------------------------------------- 1 | #------------------------------------------- 2 | # 负载均衡示例 3 | #------------------------------------------- 4 | 5 | # 设定负载均衡的服务器列表 6 | upstream demo02-server { 7 | # weigth参数表示权值,权值越高被分配到的几率越大 8 | server 127.0.0.1:9021 weight=5; 9 | server 127.0.0.1:9022 weight=1; 10 | server 127.0.0.1:9023 weight=6; 11 | } 12 | 13 | server { 14 | listen 80; 15 | server_name www.demo02.com; 16 | 17 | charset utf-8; 18 | proxy_connect_timeout 180; 19 | proxy_send_timeout 180; 20 | proxy_read_timeout 180; 21 | proxy_set_header Host $host; 22 | proxy_set_header X-Forwarded-For $remote_addr; 23 | 24 | # root /home/nginx/demos; 25 | root ../../../javaapp/src/main/webapp; 26 | 27 | location / { 28 | proxy_pass http://demo02-server; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/conf.d/demo03.conf: -------------------------------------------------------------------------------- 1 | #------------------------------------------- 2 | # 多应用共用一个主域名,不同上下文的示例 3 | #------------------------------------------- 4 | 5 | upstream home-server { 6 | server 127.0.0.1:9030; 7 | } 8 | 9 | upstream product-server { 10 | server 127.0.0.1:9031; 11 | } 12 | 13 | upstream user-server { 14 | server 127.0.0.1:9032; 15 | } 16 | 17 | server { 18 | listen 80; 19 | server_name www.demo03.com; 20 | 21 | charset utf-8; 22 | proxy_connect_timeout 180; 23 | proxy_send_timeout 180; 24 | proxy_read_timeout 180; 25 | proxy_set_header Host $host; 26 | proxy_set_header X-Forwarded-For $remote_addr; 27 | 28 | # root /home/nginx/demos; 29 | root ../../../javaapp/src/main/webapp; 30 | 31 | location / { 32 | proxy_pass http://home-server; 33 | } 34 | 35 | location /product/{ 36 | proxy_pass http://product-server; 37 | } 38 | 39 | location /user/ { 40 | proxy_pass http://user-server; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/conf.d/demo04.conf: -------------------------------------------------------------------------------- 1 | #------------------------------------------- 2 | # 前后端分离示例 3 | # root 为前端文件路径 4 | # upstream backend 配置后端服务器访问地址 5 | #------------------------------------------- 6 | 7 | upstream backend { 8 | server 127.0.0.1:9040; 9 | } 10 | 11 | server { 12 | listen 80; 13 | server_name www.demo04.com; 14 | 15 | # windows 下前后端分离场景,使用相对路径无法被识别,暂时搞不定 16 | root D:/Codes/ZP/Others/nginx-tutorial/demos/reactapp/dist; 17 | 18 | location ~ ^/api/ { 19 | proxy_pass http://backend; 20 | rewrite "^/api/(.*)$" /$1 break; 21 | } 22 | 23 | location ~* \.(json|txt|js|css|jpg|jpeg|gif|png|svg|ico|eot|otf|woff|woff2|ttf)$ {} 24 | } 25 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/conf.d/demo05.conf: -------------------------------------------------------------------------------- 1 | #------------------------------------------- 2 | # 设置文件服务器 3 | # root 为提供文件服务的根路径 4 | # Nginx 启动后,访问 http://localhost:9050 5 | #------------------------------------------- 6 | 7 | autoindex on;# 显示目录 8 | autoindex_exact_size on;# 显示文件大小 9 | autoindex_localtime on;# 显示文件时间 10 | 11 | server { 12 | charset utf-8,gbk; # windows 服务器下设置后,依然乱码,暂时无解 13 | listen 9050 default_server; 14 | listen [::]:9050 default_server; 15 | server_name _; 16 | root D:; 17 | } 18 | 19 | upstream demo05_server { 20 | server 127.0.0.1:9050; 21 | } 22 | 23 | server { 24 | listen 80; 25 | server_name www.demo05.com; 26 | 27 | charset utf-8; 28 | proxy_connect_timeout 180; 29 | proxy_send_timeout 180; 30 | proxy_read_timeout 180; 31 | 32 | location / { 33 | proxy_pass http://demo05_server; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/conf.d/demo06.conf: -------------------------------------------------------------------------------- 1 | #------------------------------------------- 2 | # 设置文件服务器 3 | # root 为提供文件服务的根路径 4 | #------------------------------------------- 5 | 6 | server { 7 | server_name www.demo06.com; # 你的域名或者 ip 8 | root D:/Codes/ZP/Others/nginx-tutorial/demos/reactadmin/build; # 你的克隆到的项目路径 9 | index index.html; # 显示首页 10 | location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|js|pdf|txt){ 11 | root D:/Codes/ZP/Others/nginx-tutorial/demos/reactadmin/build; 12 | } # 静态文件访问 13 | } -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/fastcgi.conf: -------------------------------------------------------------------------------- 1 | 2 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 3 | fastcgi_param QUERY_STRING $query_string; 4 | fastcgi_param REQUEST_METHOD $request_method; 5 | fastcgi_param CONTENT_TYPE $content_type; 6 | fastcgi_param CONTENT_LENGTH $content_length; 7 | 8 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 9 | fastcgi_param REQUEST_URI $request_uri; 10 | fastcgi_param DOCUMENT_URI $document_uri; 11 | fastcgi_param DOCUMENT_ROOT $document_root; 12 | fastcgi_param SERVER_PROTOCOL $server_protocol; 13 | fastcgi_param REQUEST_SCHEME $scheme; 14 | fastcgi_param HTTPS $https if_not_empty; 15 | 16 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 17 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 18 | 19 | fastcgi_param REMOTE_ADDR $remote_addr; 20 | fastcgi_param REMOTE_PORT $remote_port; 21 | fastcgi_param SERVER_ADDR $server_addr; 22 | fastcgi_param SERVER_PORT $server_port; 23 | fastcgi_param SERVER_NAME $server_name; 24 | 25 | # PHP only, required if PHP was built with --enable-force-cgi-redirect 26 | fastcgi_param REDIRECT_STATUS 200; 27 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/fastcgi_params: -------------------------------------------------------------------------------- 1 | 2 | fastcgi_param QUERY_STRING $query_string; 3 | fastcgi_param REQUEST_METHOD $request_method; 4 | fastcgi_param CONTENT_TYPE $content_type; 5 | fastcgi_param CONTENT_LENGTH $content_length; 6 | 7 | fastcgi_param SCRIPT_NAME $fastcgi_script_name; 8 | fastcgi_param REQUEST_URI $request_uri; 9 | fastcgi_param DOCUMENT_URI $document_uri; 10 | fastcgi_param DOCUMENT_ROOT $document_root; 11 | fastcgi_param SERVER_PROTOCOL $server_protocol; 12 | fastcgi_param REQUEST_SCHEME $scheme; 13 | fastcgi_param HTTPS $https if_not_empty; 14 | 15 | fastcgi_param GATEWAY_INTERFACE CGI/1.1; 16 | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 17 | 18 | fastcgi_param REMOTE_ADDR $remote_addr; 19 | fastcgi_param REMOTE_PORT $remote_port; 20 | fastcgi_param SERVER_ADDR $server_addr; 21 | fastcgi_param SERVER_PORT $server_port; 22 | fastcgi_param SERVER_NAME $server_name; 23 | 24 | # PHP only, required if PHP was built with --enable-force-cgi-redirect 25 | fastcgi_param REDIRECT_STATUS 200; 26 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/koi-utf: -------------------------------------------------------------------------------- 1 | 2 | # This map is not a full koi8-r <> utf8 map: it does not contain 3 | # box-drawing and some other characters. Besides this map contains 4 | # several koi8-u and Byelorussian letters which are not in koi8-r. 5 | # If you need a full and standard map, use contrib/unicode2nginx/koi-utf 6 | # map instead. 7 | 8 | charset_map koi8-r utf-8 { 9 | 10 | 80 E282AC ; # euro 11 | 12 | 95 E280A2 ; # bullet 13 | 14 | 9A C2A0 ; #   15 | 16 | 9E C2B7 ; # · 17 | 18 | A3 D191 ; # small yo 19 | A4 D194 ; # small Ukrainian ye 20 | 21 | A6 D196 ; # small Ukrainian i 22 | A7 D197 ; # small Ukrainian yi 23 | 24 | AD D291 ; # small Ukrainian soft g 25 | AE D19E ; # small Byelorussian short u 26 | 27 | B0 C2B0 ; # ° 28 | 29 | B3 D081 ; # capital YO 30 | B4 D084 ; # capital Ukrainian YE 31 | 32 | B6 D086 ; # capital Ukrainian I 33 | B7 D087 ; # capital Ukrainian YI 34 | 35 | B9 E28496 ; # numero sign 36 | 37 | BD D290 ; # capital Ukrainian soft G 38 | BE D18E ; # capital Byelorussian short U 39 | 40 | BF C2A9 ; # (C) 41 | 42 | C0 D18E ; # small yu 43 | C1 D0B0 ; # small a 44 | C2 D0B1 ; # small b 45 | C3 D186 ; # small ts 46 | C4 D0B4 ; # small d 47 | C5 D0B5 ; # small ye 48 | C6 D184 ; # small f 49 | C7 D0B3 ; # small g 50 | C8 D185 ; # small kh 51 | C9 D0B8 ; # small i 52 | CA D0B9 ; # small j 53 | CB D0BA ; # small k 54 | CC D0BB ; # small l 55 | CD D0BC ; # small m 56 | CE D0BD ; # small n 57 | CF D0BE ; # small o 58 | 59 | D0 D0BF ; # small p 60 | D1 D18F ; # small ya 61 | D2 D180 ; # small r 62 | D3 D181 ; # small s 63 | D4 D182 ; # small t 64 | D5 D183 ; # small u 65 | D6 D0B6 ; # small zh 66 | D7 D0B2 ; # small v 67 | D8 D18C ; # small soft sign 68 | D9 D18B ; # small y 69 | DA D0B7 ; # small z 70 | DB D188 ; # small sh 71 | DC D18D ; # small e 72 | DD D189 ; # small shch 73 | DE D187 ; # small ch 74 | DF D18A ; # small hard sign 75 | 76 | E0 D0AE ; # capital YU 77 | E1 D090 ; # capital A 78 | E2 D091 ; # capital B 79 | E3 D0A6 ; # capital TS 80 | E4 D094 ; # capital D 81 | E5 D095 ; # capital YE 82 | E6 D0A4 ; # capital F 83 | E7 D093 ; # capital G 84 | E8 D0A5 ; # capital KH 85 | E9 D098 ; # capital I 86 | EA D099 ; # capital J 87 | EB D09A ; # capital K 88 | EC D09B ; # capital L 89 | ED D09C ; # capital M 90 | EE D09D ; # capital N 91 | EF D09E ; # capital O 92 | 93 | F0 D09F ; # capital P 94 | F1 D0AF ; # capital YA 95 | F2 D0A0 ; # capital R 96 | F3 D0A1 ; # capital S 97 | F4 D0A2 ; # capital T 98 | F5 D0A3 ; # capital U 99 | F6 D096 ; # capital ZH 100 | F7 D092 ; # capital V 101 | F8 D0AC ; # capital soft sign 102 | F9 D0AB ; # capital Y 103 | FA D097 ; # capital Z 104 | FB D0A8 ; # capital SH 105 | FC D0AD ; # capital E 106 | FD D0A9 ; # capital SHCH 107 | FE D0A7 ; # capital CH 108 | FF D0AA ; # capital hard sign 109 | } 110 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/koi-win: -------------------------------------------------------------------------------- 1 | 2 | charset_map koi8-r windows-1251 { 3 | 4 | 80 88 ; # euro 5 | 6 | 95 95 ; # bullet 7 | 8 | 9A A0 ; #   9 | 10 | 9E B7 ; # · 11 | 12 | A3 B8 ; # small yo 13 | A4 BA ; # small Ukrainian ye 14 | 15 | A6 B3 ; # small Ukrainian i 16 | A7 BF ; # small Ukrainian yi 17 | 18 | AD B4 ; # small Ukrainian soft g 19 | AE A2 ; # small Byelorussian short u 20 | 21 | B0 B0 ; # ° 22 | 23 | B3 A8 ; # capital YO 24 | B4 AA ; # capital Ukrainian YE 25 | 26 | B6 B2 ; # capital Ukrainian I 27 | B7 AF ; # capital Ukrainian YI 28 | 29 | B9 B9 ; # numero sign 30 | 31 | BD A5 ; # capital Ukrainian soft G 32 | BE A1 ; # capital Byelorussian short U 33 | 34 | BF A9 ; # (C) 35 | 36 | C0 FE ; # small yu 37 | C1 E0 ; # small a 38 | C2 E1 ; # small b 39 | C3 F6 ; # small ts 40 | C4 E4 ; # small d 41 | C5 E5 ; # small ye 42 | C6 F4 ; # small f 43 | C7 E3 ; # small g 44 | C8 F5 ; # small kh 45 | C9 E8 ; # small i 46 | CA E9 ; # small j 47 | CB EA ; # small k 48 | CC EB ; # small l 49 | CD EC ; # small m 50 | CE ED ; # small n 51 | CF EE ; # small o 52 | 53 | D0 EF ; # small p 54 | D1 FF ; # small ya 55 | D2 F0 ; # small r 56 | D3 F1 ; # small s 57 | D4 F2 ; # small t 58 | D5 F3 ; # small u 59 | D6 E6 ; # small zh 60 | D7 E2 ; # small v 61 | D8 FC ; # small soft sign 62 | D9 FB ; # small y 63 | DA E7 ; # small z 64 | DB F8 ; # small sh 65 | DC FD ; # small e 66 | DD F9 ; # small shch 67 | DE F7 ; # small ch 68 | DF FA ; # small hard sign 69 | 70 | E0 DE ; # capital YU 71 | E1 C0 ; # capital A 72 | E2 C1 ; # capital B 73 | E3 D6 ; # capital TS 74 | E4 C4 ; # capital D 75 | E5 C5 ; # capital YE 76 | E6 D4 ; # capital F 77 | E7 C3 ; # capital G 78 | E8 D5 ; # capital KH 79 | E9 C8 ; # capital I 80 | EA C9 ; # capital J 81 | EB CA ; # capital K 82 | EC CB ; # capital L 83 | ED CC ; # capital M 84 | EE CD ; # capital N 85 | EF CE ; # capital O 86 | 87 | F0 CF ; # capital P 88 | F1 DF ; # capital YA 89 | F2 D0 ; # capital R 90 | F3 D1 ; # capital S 91 | F4 D2 ; # capital T 92 | F5 D3 ; # capital U 93 | F6 C6 ; # capital ZH 94 | F7 C2 ; # capital V 95 | F8 DC ; # capital soft sign 96 | F9 DB ; # capital Y 97 | FA C7 ; # capital Z 98 | FB D8 ; # capital SH 99 | FC DD ; # capital E 100 | FD D9 ; # capital SHCH 101 | FE D7 ; # capital CH 102 | FF DA ; # capital hard sign 103 | } 104 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/svg+xml svg svgz; 20 | image/tiff tif tiff; 21 | image/vnd.wap.wbmp wbmp; 22 | image/webp webp; 23 | image/x-icon ico; 24 | image/x-jng jng; 25 | image/x-ms-bmp bmp; 26 | 27 | application/font-woff woff; 28 | application/java-archive jar war ear; 29 | application/json json; 30 | application/mac-binhex40 hqx; 31 | application/msword doc; 32 | application/pdf pdf; 33 | application/postscript ps eps ai; 34 | application/rtf rtf; 35 | application/vnd.apple.mpegurl m3u8; 36 | application/vnd.google-earth.kml+xml kml; 37 | application/vnd.google-earth.kmz kmz; 38 | application/vnd.ms-excel xls; 39 | application/vnd.ms-fontobject eot; 40 | application/vnd.ms-powerpoint ppt; 41 | application/vnd.oasis.opendocument.graphics odg; 42 | application/vnd.oasis.opendocument.presentation odp; 43 | application/vnd.oasis.opendocument.spreadsheet ods; 44 | application/vnd.oasis.opendocument.text odt; 45 | application/vnd.openxmlformats-officedocument.presentationml.presentation 46 | pptx; 47 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 48 | xlsx; 49 | application/vnd.openxmlformats-officedocument.wordprocessingml.document 50 | docx; 51 | application/vnd.wap.wmlc wmlc; 52 | application/x-7z-compressed 7z; 53 | application/x-cocoa cco; 54 | application/x-java-archive-diff jardiff; 55 | application/x-java-jnlp-file jnlp; 56 | application/x-makeself run; 57 | application/x-perl pl pm; 58 | application/x-pilot prc pdb; 59 | application/x-rar-compressed rar; 60 | application/x-redhat-package-manager rpm; 61 | application/x-sea sea; 62 | application/x-shockwave-flash swf; 63 | application/x-stuffit sit; 64 | application/x-tcl tcl tk; 65 | application/x-x509-ca-cert der pem crt; 66 | application/x-xpinstall xpi; 67 | application/xhtml+xml xhtml; 68 | application/xspf+xml xspf; 69 | application/zip zip; 70 | 71 | application/octet-stream bin exe dll; 72 | application/octet-stream deb; 73 | application/octet-stream dmg; 74 | application/octet-stream iso img; 75 | application/octet-stream msi msp msm; 76 | 77 | audio/midi mid midi kar; 78 | audio/mpeg mp3; 79 | audio/ogg ogg; 80 | audio/x-m4a m4a; 81 | audio/x-realaudio ra; 82 | 83 | video/3gpp 3gpp 3gp; 84 | video/mp2t ts; 85 | video/mp4 mp4; 86 | video/mpeg mpeg mpg; 87 | video/quicktime mov; 88 | video/webm webm; 89 | video/x-flv flv; 90 | video/x-m4v m4v; 91 | video/x-mng mng; 92 | video/x-ms-asf asx asf; 93 | video/x-ms-wmv wmv; 94 | video/x-msvideo avi; 95 | } 96 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | error_log logs/nginx-error.log info; 3 | events { 4 | worker_connections 1024; 5 | } 6 | 7 | http { 8 | default_type application/octet-stream; 9 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 10 | '$status $body_bytes_sent "$http_referer" ' 11 | '"$http_user_agent" "$http_x_forwarded_for"'; 12 | access_log logs/nginx-http-access.log; 13 | sendfile on; 14 | rewrite_log on; 15 | keepalive_timeout 180; 16 | 17 | client_max_body_size 20m; 18 | client_body_buffer_size 128k; 19 | 20 | #common header set 21 | proxy_http_version 1.1; 22 | proxy_set_header Host $host; 23 | proxy_set_header X-Real-IP $remote_addr; 24 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 25 | proxy_set_header X-Forwarded-Proto $scheme; 26 | proxy_set_header Upgrade $http_upgrade; 27 | proxy_set_header Connection "upgrade"; 28 | 29 | include mime.types; 30 | include conf.d/*.conf; 31 | } 32 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/scgi_params: -------------------------------------------------------------------------------- 1 | 2 | scgi_param REQUEST_METHOD $request_method; 3 | scgi_param REQUEST_URI $request_uri; 4 | scgi_param QUERY_STRING $query_string; 5 | scgi_param CONTENT_TYPE $content_type; 6 | 7 | scgi_param DOCUMENT_URI $document_uri; 8 | scgi_param DOCUMENT_ROOT $document_root; 9 | scgi_param SCGI 1; 10 | scgi_param SERVER_PROTOCOL $server_protocol; 11 | scgi_param REQUEST_SCHEME $scheme; 12 | scgi_param HTTPS $https if_not_empty; 13 | 14 | scgi_param REMOTE_ADDR $remote_addr; 15 | scgi_param REMOTE_PORT $remote_port; 16 | scgi_param SERVER_PORT $server_port; 17 | scgi_param SERVER_NAME $server_name; 18 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/uwsgi_params: -------------------------------------------------------------------------------- 1 | 2 | uwsgi_param QUERY_STRING $query_string; 3 | uwsgi_param REQUEST_METHOD $request_method; 4 | uwsgi_param CONTENT_TYPE $content_type; 5 | uwsgi_param CONTENT_LENGTH $content_length; 6 | 7 | uwsgi_param REQUEST_URI $request_uri; 8 | uwsgi_param PATH_INFO $document_uri; 9 | uwsgi_param DOCUMENT_ROOT $document_root; 10 | uwsgi_param SERVER_PROTOCOL $server_protocol; 11 | uwsgi_param REQUEST_SCHEME $scheme; 12 | uwsgi_param HTTPS $https if_not_empty; 13 | 14 | uwsgi_param REMOTE_ADDR $remote_addr; 15 | uwsgi_param REMOTE_PORT $remote_port; 16 | uwsgi_param SERVER_PORT $server_port; 17 | uwsgi_param SERVER_NAME $server_name; 18 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/conf/win-utf: -------------------------------------------------------------------------------- 1 | 2 | # This map is not a full windows-1251 <> utf8 map: it does not 3 | # contain Serbian and Macedonian letters. If you need a full map, 4 | # use contrib/unicode2nginx/win-utf map instead. 5 | 6 | charset_map windows-1251 utf-8 { 7 | 8 | 82 E2809A ; # single low-9 quotation mark 9 | 10 | 84 E2809E ; # double low-9 quotation mark 11 | 85 E280A6 ; # ellipsis 12 | 86 E280A0 ; # dagger 13 | 87 E280A1 ; # double dagger 14 | 88 E282AC ; # euro 15 | 89 E280B0 ; # per mille 16 | 17 | 91 E28098 ; # left single quotation mark 18 | 92 E28099 ; # right single quotation mark 19 | 93 E2809C ; # left double quotation mark 20 | 94 E2809D ; # right double quotation mark 21 | 95 E280A2 ; # bullet 22 | 96 E28093 ; # en dash 23 | 97 E28094 ; # em dash 24 | 25 | 99 E284A2 ; # trade mark sign 26 | 27 | A0 C2A0 ; #   28 | A1 D18E ; # capital Byelorussian short U 29 | A2 D19E ; # small Byelorussian short u 30 | 31 | A4 C2A4 ; # currency sign 32 | A5 D290 ; # capital Ukrainian soft G 33 | A6 C2A6 ; # borken bar 34 | A7 C2A7 ; # section sign 35 | A8 D081 ; # capital YO 36 | A9 C2A9 ; # (C) 37 | AA D084 ; # capital Ukrainian YE 38 | AB C2AB ; # left-pointing double angle quotation mark 39 | AC C2AC ; # not sign 40 | AD C2AD ; # soft hypen 41 | AE C2AE ; # (R) 42 | AF D087 ; # capital Ukrainian YI 43 | 44 | B0 C2B0 ; # ° 45 | B1 C2B1 ; # plus-minus sign 46 | B2 D086 ; # capital Ukrainian I 47 | B3 D196 ; # small Ukrainian i 48 | B4 D291 ; # small Ukrainian soft g 49 | B5 C2B5 ; # micro sign 50 | B6 C2B6 ; # pilcrow sign 51 | B7 C2B7 ; # · 52 | B8 D191 ; # small yo 53 | B9 E28496 ; # numero sign 54 | BA D194 ; # small Ukrainian ye 55 | BB C2BB ; # right-pointing double angle quotation mark 56 | 57 | BF D197 ; # small Ukrainian yi 58 | 59 | C0 D090 ; # capital A 60 | C1 D091 ; # capital B 61 | C2 D092 ; # capital V 62 | C3 D093 ; # capital G 63 | C4 D094 ; # capital D 64 | C5 D095 ; # capital YE 65 | C6 D096 ; # capital ZH 66 | C7 D097 ; # capital Z 67 | C8 D098 ; # capital I 68 | C9 D099 ; # capital J 69 | CA D09A ; # capital K 70 | CB D09B ; # capital L 71 | CC D09C ; # capital M 72 | CD D09D ; # capital N 73 | CE D09E ; # capital O 74 | CF D09F ; # capital P 75 | 76 | D0 D0A0 ; # capital R 77 | D1 D0A1 ; # capital S 78 | D2 D0A2 ; # capital T 79 | D3 D0A3 ; # capital U 80 | D4 D0A4 ; # capital F 81 | D5 D0A5 ; # capital KH 82 | D6 D0A6 ; # capital TS 83 | D7 D0A7 ; # capital CH 84 | D8 D0A8 ; # capital SH 85 | D9 D0A9 ; # capital SHCH 86 | DA D0AA ; # capital hard sign 87 | DB D0AB ; # capital Y 88 | DC D0AC ; # capital soft sign 89 | DD D0AD ; # capital E 90 | DE D0AE ; # capital YU 91 | DF D0AF ; # capital YA 92 | 93 | E0 D0B0 ; # small a 94 | E1 D0B1 ; # small b 95 | E2 D0B2 ; # small v 96 | E3 D0B3 ; # small g 97 | E4 D0B4 ; # small d 98 | E5 D0B5 ; # small ye 99 | E6 D0B6 ; # small zh 100 | E7 D0B7 ; # small z 101 | E8 D0B8 ; # small i 102 | E9 D0B9 ; # small j 103 | EA D0BA ; # small k 104 | EB D0BB ; # small l 105 | EC D0BC ; # small m 106 | ED D0BD ; # small n 107 | EE D0BE ; # small o 108 | EF D0BF ; # small p 109 | 110 | F0 D180 ; # small r 111 | F1 D181 ; # small s 112 | F2 D182 ; # small t 113 | F3 D183 ; # small u 114 | F4 D184 ; # small f 115 | F5 D185 ; # small kh 116 | F6 D186 ; # small ts 117 | F7 D187 ; # small ch 118 | F8 D188 ; # small sh 119 | F9 D189 ; # small shch 120 | FA D18A ; # small hard sign 121 | FB D18B ; # small y 122 | FC D18C ; # small soft sign 123 | FD D18D ; # small e 124 | FE D18E ; # small yu 125 | FF D18F ; # small ya 126 | } 127 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/contrib/README: -------------------------------------------------------------------------------- 1 | 2 | geo2nginx.pl by Andrei Nigmatulin 3 | 4 | The perl script to convert CSV geoip database ( free download 5 | at http://www.maxmind.com/app/geoip_country ) to format, suitable 6 | for use by the ngx_http_geo_module. 7 | 8 | 9 | unicode2nginx by Maxim Dounin 10 | 11 | The perl script to convert unicode mappings ( available 12 | at http://www.unicode.org/Public/MAPPINGS/ ) to the nginx 13 | configuration file format. 14 | Two generated full maps for windows-1251 and koi8-r. 15 | 16 | 17 | vim by Evan Miller 18 | 19 | Syntax highlighting of nginx configuration for vim, to be 20 | placed into ~/.vim/. 21 | 22 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/contrib/geo2nginx.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # (c) Andrei Nigmatulin, 2005 4 | # 5 | # this script provided "as is", without any warranties. use it at your own risk. 6 | # 7 | # special thanx to Andrew Sitnikov for perl port 8 | # 9 | # this script converts CSV geoip database (free download at http://www.maxmind.com/app/geoip_country) 10 | # to format, suitable for use with nginx_http_geo module (http://sysoev.ru/nginx) 11 | # 12 | # for example, line with ip range 13 | # 14 | # "62.16.68.0","62.16.127.255","1041253376","1041268735","RU","Russian Federation" 15 | # 16 | # will be converted to four subnetworks: 17 | # 18 | # 62.16.68.0/22 RU; 19 | # 62.16.72.0/21 RU; 20 | # 62.16.80.0/20 RU; 21 | # 62.16.96.0/19 RU; 22 | 23 | 24 | use warnings; 25 | use strict; 26 | 27 | while( ){ 28 | if (/"[^"]+","[^"]+","([^"]+)","([^"]+)","([^"]+)"/){ 29 | print_subnets($1, $2, $3); 30 | } 31 | } 32 | 33 | sub print_subnets { 34 | my ($a1, $a2, $c) = @_; 35 | my $l; 36 | while ($a1 <= $a2) { 37 | for ($l = 0; ($a1 & (1 << $l)) == 0 && ($a1 + ((1 << ($l + 1)) - 1)) <= $a2; $l++){}; 38 | print long2ip($a1) . "/" . (32 - $l) . " " . $c . ";\n"; 39 | $a1 += (1 << $l); 40 | } 41 | } 42 | 43 | sub long2ip { 44 | my $ip = shift; 45 | 46 | my $str = 0; 47 | 48 | $str = ($ip & 255); 49 | 50 | $ip >>= 8; 51 | $str = ($ip & 255).".$str"; 52 | 53 | $ip >>= 8; 54 | $str = ($ip & 255).".$str"; 55 | 56 | $ip >>= 8; 57 | $str = ($ip & 255).".$str"; 58 | } 59 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/contrib/unicode2nginx/unicode-to-nginx.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | # Convert unicode mappings to nginx configuration file format. 4 | 5 | # You may find useful mappings in various places, including 6 | # unicode.org official site: 7 | # 8 | # http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT 9 | # http://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT 10 | 11 | # Needs perl 5.6 or later. 12 | 13 | # Written by Maxim Dounin, mdounin@mdounin.ru 14 | 15 | ############################################################################### 16 | 17 | require 5.006; 18 | 19 | while (<>) { 20 | # Skip comments and empty lines 21 | 22 | next if /^#/; 23 | next if /^\s*$/; 24 | chomp; 25 | 26 | # Convert mappings 27 | 28 | if (/^\s*0x(..)\s*0x(....)\s*(#.*)/) { 29 | # Mapping "#" 30 | my $cs_code = $1; 31 | my $un_code = $2; 32 | my $un_name = $3; 33 | 34 | # Produce UTF-8 sequence from character code; 35 | 36 | my $un_utf8 = join('', 37 | map { sprintf("%02X", $_) } 38 | unpack("U0C*", pack("U", hex($un_code))) 39 | ); 40 | 41 | print " $cs_code $un_utf8 ; $un_name\n"; 42 | 43 | } else { 44 | warn "Unrecognized line: '$_'"; 45 | } 46 | } 47 | 48 | ############################################################################### 49 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/contrib/vim/ftdetect/nginx.vim: -------------------------------------------------------------------------------- 1 | au BufRead,BufNewFile *.nginx set ft=nginx 2 | au BufRead,BufNewFile */etc/nginx/* set ft=nginx 3 | au BufRead,BufNewFile */usr/local/nginx/conf/* set ft=nginx 4 | au BufRead,BufNewFile nginx.conf set ft=nginx 5 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/contrib/vim/ftplugin/nginx.vim: -------------------------------------------------------------------------------- 1 | setlocal commentstring=#\ %s 2 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/contrib/vim/indent/nginx.vim: -------------------------------------------------------------------------------- 1 | if exists("b:did_indent") 2 | finish 3 | endif 4 | let b:did_indent = 1 5 | 6 | setlocal indentexpr= 7 | 8 | " cindent actually works for nginx' simple file structure 9 | setlocal cindent 10 | " Just make sure that the comments are not reset as defs would be. 11 | setlocal cinkeys-=0# 12 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/docs/LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2018 Igor Sysoev 3 | * Copyright (C) 2011-2018 Nginx, Inc. 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/docs/PCRE.LICENCE: -------------------------------------------------------------------------------- 1 | PCRE LICENCE 2 | ------------ 3 | 4 | PCRE is a library of functions to support regular expressions whose syntax 5 | and semantics are as close as possible to those of the Perl 5 language. 6 | 7 | Release 8 of PCRE is distributed under the terms of the "BSD" licence, as 8 | specified below. The documentation for PCRE, supplied in the "doc" 9 | directory, is distributed under the same terms as the software itself. The data 10 | in the testdata directory is not copyrighted and is in the public domain. 11 | 12 | The basic library functions are written in C and are freestanding. Also 13 | included in the distribution is a set of C++ wrapper functions, and a 14 | just-in-time compiler that can be used to optimize pattern matching. These 15 | are both optional features that can be omitted when the library is built. 16 | 17 | 18 | THE BASIC LIBRARY FUNCTIONS 19 | --------------------------- 20 | 21 | Written by: Philip Hazel 22 | Email local part: ph10 23 | Email domain: cam.ac.uk 24 | 25 | University of Cambridge Computing Service, 26 | Cambridge, England. 27 | 28 | Copyright (c) 1997-2018 University of Cambridge 29 | All rights reserved. 30 | 31 | 32 | PCRE JUST-IN-TIME COMPILATION SUPPORT 33 | ------------------------------------- 34 | 35 | Written by: Zoltan Herczeg 36 | Email local part: hzmester 37 | Emain domain: freemail.hu 38 | 39 | Copyright(c) 2010-2018 Zoltan Herczeg 40 | All rights reserved. 41 | 42 | 43 | STACK-LESS JUST-IN-TIME COMPILER 44 | -------------------------------- 45 | 46 | Written by: Zoltan Herczeg 47 | Email local part: hzmester 48 | Emain domain: freemail.hu 49 | 50 | Copyright(c) 2009-2018 Zoltan Herczeg 51 | All rights reserved. 52 | 53 | 54 | THE C++ WRAPPER FUNCTIONS 55 | ------------------------- 56 | 57 | Contributed by: Google Inc. 58 | 59 | Copyright (c) 2007-2012, Google Inc. 60 | All rights reserved. 61 | 62 | 63 | THE "BSD" LICENCE 64 | ----------------- 65 | 66 | Redistribution and use in source and binary forms, with or without 67 | modification, are permitted provided that the following conditions are met: 68 | 69 | * Redistributions of source code must retain the above copyright notice, 70 | this list of conditions and the following disclaimer. 71 | 72 | * Redistributions in binary form must reproduce the above copyright 73 | notice, this list of conditions and the following disclaimer in the 74 | documentation and/or other materials provided with the distribution. 75 | 76 | * Neither the name of the University of Cambridge nor the name of Google 77 | Inc. nor the names of their contributors may be used to endorse or 78 | promote products derived from this software without specific prior 79 | written permission. 80 | 81 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 82 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 83 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 84 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 85 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 86 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 87 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 88 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 89 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 90 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 91 | POSSIBILITY OF SUCH DAMAGE. 92 | 93 | End 94 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/docs/README: -------------------------------------------------------------------------------- 1 | 2 | Documentation is available at http://nginx.org 3 | 4 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/docs/zlib.LICENSE: -------------------------------------------------------------------------------- 1 | (C) 1995-2017 Jean-loup Gailly and Mark Adler 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | 19 | Jean-loup Gailly Mark Adler 20 | jloup@gzip.org madler@alumni.caltech.edu 21 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/html/50x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 12 | 13 | 14 |

An error occurred.

15 |

Sorry, the page you are looking for is currently unavailable.
16 | Please try again later.

17 |

If you are the system administrator of this resource then you should check 18 | the error log for details.

19 |

Faithfully yours, nginx.

20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Welcome to nginx! 5 | 12 | 13 | 14 |

Welcome to nginx!

15 |

If you see this page, the nginx web server is successfully installed and 16 | working. Further configuration is required.

17 | 18 |

For online documentation and support please refer to 19 | nginx.org.
20 | Commercial support is available at 21 | nginx.com.

22 | 23 |

Thank you for using nginx.

24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/nginx-start.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem 1. 如果目录不存在 logs 目录,则创建 4 | if not exist %~dp0logs ( 5 | echo %~dp0logs is not exists, create it. 6 | md %~dp0logs 7 | ) 8 | 9 | rem 2. 如果目录不存在 temp 目录,则创建 10 | if not exist %~dp0temp ( 11 | echo %~dp0temp is not exists, create it. 12 | md %~dp0temp 13 | ) 14 | 15 | rem 3. 指定 conf/nginx.conf ,启动 nginx 16 | nginx.exe -t -c conf/nginx.conf 17 | start nginx 18 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/nginx-stop.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | nginx.exe -s stop 4 | -------------------------------------------------------------------------------- /examples/nginx-1.14.0/nginx.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/nginx-1.14.0/nginx.exe -------------------------------------------------------------------------------- /examples/nginx.conf: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- 2 | # 本文件是 nginx-1.14.0 的默认配置文件 3 | # 我对一些重要参数加了中文注释 4 | # ---------------------------------------------------- 5 | 6 | # 运行用户 7 | #user nobody; 8 | 9 | # 启动进程,通常设置成和 CPU 的数量相等 10 | worker_processes 1; 11 | 12 | # 全局错误日志 13 | #error_log logs/error.log; 14 | #error_log logs/error.log notice; 15 | #error_log logs/error.log info; 16 | 17 | # PID 文件,记录当前启动的 nginx 的进程 ID 18 | #pid logs/nginx.pid; 19 | 20 | # 工作模式及连接数上限 21 | events { 22 | worker_connections 1024; #单个后台 worker process 进程的最大并发链接数 23 | } 24 | 25 | # 设定 http 服务器,利用它的反向代理功能提供负载均衡支持 26 | http { 27 | # 设定 mime 类型(邮件支持类型),类型由 mime.types 文件定义 28 | include mime.types; 29 | default_type application/octet-stream; 30 | 31 | # 设定日志格式 32 | #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 33 | # '$status $body_bytes_sent "$http_referer" ' 34 | # '"$http_user_agent" "$http_x_forwarded_for"'; 35 | 36 | #access_log logs/access.log main; 37 | 38 | # sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用, 39 | # 必须设为 on,如果用来进行下载等应用磁盘 IO 重负载应用,可设置为 off,以平衡磁盘与网络 I/O 处理速度,降低系统的 uptime。 40 | sendfile on; 41 | #tcp_nopush on; 42 | 43 | # 连接超时时间 44 | #keepalive_timeout 0; 45 | keepalive_timeout 65; 46 | 47 | # gzip 压缩开关 48 | #gzip on; 49 | 50 | # 设定实际的服务器列表 51 | server { 52 | # 监听 80 端口,80 端口是知名端口号,用于HTTP协议 53 | listen 80; 54 | 55 | # 定义使用的访问域名(host) 56 | server_name localhost; 57 | 58 | # 编码格式 59 | #charset utf-8; 60 | 61 | #access_log logs/host.access.log main; 62 | 63 | # 反向代理的路径(和 upstream 绑定),location 后面设置映射的路径 64 | location / { 65 | root html; 66 | index index.html index.htm; 67 | } 68 | 69 | #error_page 404 /404.html; 70 | 71 | # redirect server error pages to the static page /50x.html 72 | # 73 | error_page 500 502 503 504 /50x.html; 74 | location = /50x.html { 75 | root html; 76 | } 77 | 78 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 79 | # 80 | #location ~ \.php$ { 81 | # proxy_pass http://127.0.0.1; 82 | #} 83 | 84 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 85 | # 86 | #location ~ \.php$ { 87 | # root html; 88 | # fastcgi_pass 127.0.0.1:9000; 89 | # fastcgi_index index.php; 90 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 91 | # include fastcgi_params; 92 | #} 93 | 94 | # deny access to .htaccess files, if Apache's document root 95 | # concurs with nginx's one 96 | # 97 | #location ~ /\.ht { 98 | # deny all; 99 | #} 100 | } 101 | 102 | 103 | # another virtual host using mix of IP-, name-, and port-based configuration 104 | # 105 | #server { 106 | # listen 8000; 107 | # listen somename:8080; 108 | # server_name somename alias another.alias; 109 | 110 | # location / { 111 | # root html; 112 | # index index.html index.htm; 113 | # } 114 | #} 115 | 116 | 117 | # HTTPS server 118 | # 119 | #server { 120 | # listen 443 ssl; 121 | # server_name localhost; 122 | 123 | # ssl_certificate cert.pem; 124 | # ssl_certificate_key cert.key; 125 | 126 | # ssl_session_cache shared:SSL:1m; 127 | # ssl_session_timeout 5m; 128 | 129 | # ssl_ciphers HIGH:!aNULL:!MD5; 130 | # ssl_prefer_server_ciphers on; 131 | 132 | # location / { 133 | # root html; 134 | # index index.html index.htm; 135 | # } 136 | #} 137 | 138 | } 139 | -------------------------------------------------------------------------------- /examples/reactadmin/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/reactadmin/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /examples/reactadmin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-admin", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.7.0", 7 | "react-dom": "^16.7.0", 8 | "react-scripts": "2.1.3" 9 | }, 10 | "scripts": { 11 | "start": "react-scripts start", 12 | "build": "react-scripts build", 13 | "test": "react-scripts test", 14 | "eject": "react-scripts eject" 15 | }, 16 | "eslintConfig": { 17 | "extends": "react-app" 18 | }, 19 | "browserslist": [ 20 | ">0.2%", 21 | "not dead", 22 | "not ie <= 11", 23 | "not op_mini all" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /examples/reactadmin/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/reactadmin/public/favicon.ico -------------------------------------------------------------------------------- /examples/reactadmin/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/reactadmin/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/reactadmin/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282C34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61DAFB; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/reactadmin/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import logo from './logo.svg' 3 | import './App.css' 4 | 5 | class App extends Component { 6 | render() { 7 | return ( 8 | < div 9 | className = 'App' > 10 | < header 11 | className = 'App-header' > 12 | < img 13 | src = { logo } 14 | className = 'App-logo' 15 | alt = 'logo' / > 16 | < p > 17 | Edit < code > src / App.js < /code> and save to reload. 18 | < /p> 19 | < a 20 | className = 'App-link' 21 | href = 'https://reactjs.org' 22 | target = '_blank' 23 | rel = 'noopener noreferrer' 24 | > 25 | Learn 26 | React 27 | < /a> 28 | < /header> 29 | < /div> 30 | ) 31 | 32 | } 33 | } 34 | 35 | export default App 36 | -------------------------------------------------------------------------------- /examples/reactadmin/src/App.test.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | import App from './App' 3 | 4 | it('renders without crashing', () => { 5 | const div = document.createElement('div') 6 | ReactDOM.render( < App / >, div 7 | ) 8 | 9 | ReactDOM.unmountComponentAtNode(div) 10 | }) 11 | -------------------------------------------------------------------------------- /examples/reactadmin/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /examples/reactadmin/src/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | import './index.css' 3 | import App from './App' 4 | import * as serviceWorker from './serviceWorker' 5 | 6 | ReactDOM.render( < App / >, document.getElementById('root') 7 | ) 8 | 9 | 10 | // If you want your app to work offline and load faster, you can change 11 | // unregister() to register() below. Note this comes with some pitfalls. 12 | // Learn more about service workers: http://bit.ly/CRA-PWA 13 | serviceWorker.unregister() 14 | -------------------------------------------------------------------------------- /examples/reactadmin/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/reactadmin/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ) 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href) 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config) 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ) 48 | }) 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config) 52 | } 53 | }) 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing 63 | if (installingWorker == null) { 64 | return 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ) 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration) 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.') 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration) 90 | } 91 | } 92 | } 93 | } 94 | } 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error) 98 | }) 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type') 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload() 115 | }) 116 | }) 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config) 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ) 126 | }) 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister() 133 | }) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /examples/reactapp/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false 7 | } 8 | ], 9 | "react", 10 | "stage-0" 11 | ], 12 | "plugins": [ 13 | "react-hot-loader/babel", 14 | "syntax-dynamic-import", 15 | "transform-runtime", 16 | [ 17 | "import", 18 | [ 19 | { 20 | "libraryName": "antd", 21 | "style": "css" 22 | } 23 | ] 24 | ] 25 | ], 26 | "env": { 27 | "test": { 28 | "presets": [ 29 | "env", 30 | "react", 31 | "stage-0" 32 | ] 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/reactapp/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | # 所有文件换行以 Unix like 风格(LF),win 格式特定的除外(bat) 5 | # 缩进 java 4 个空格,其他所有文件 2 个空格 6 | 7 | root = true 8 | 9 | [*] 10 | # Unix-style newlines with a newline ending every file 11 | end_of_line = lf 12 | 13 | # Change these settings to your own preference 14 | indent_style = space 15 | indent_size = 2 16 | 17 | # We recommend you to keep these unchanged 18 | charset = utf-8 19 | trim_trailing_whitespace = true 20 | insert_final_newline = true 21 | 22 | [*.bat] 23 | end_of_line = crlf 24 | 25 | [*.java] 26 | indent_style = space 27 | indent_size = 4 28 | 29 | [*.md] 30 | trim_trailing_whitespace = false 31 | -------------------------------------------------------------------------------- /examples/reactapp/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint-config-airbnb" 4 | ], 5 | "parser": "babel-eslint", 6 | "globals": { 7 | "Action": false, 8 | "__DEV__": false, 9 | "__DEV__LOG__": false, 10 | "__DEV__LOG__DIFF__": true, 11 | "__DEV__IMMUTABLE_CHECK__": false, 12 | "__PROD__": false, 13 | "__DEBUG__": false, 14 | "__DEBUG_NEW_WINDOW__": false, 15 | "__BASENAME__": false, 16 | "Image": {}, 17 | "FileReader": {}, 18 | "Request": {}, 19 | "fetch": {}, 20 | "XMLHttpRequest": {} 21 | }, 22 | "rules": { 23 | "arrow-body-style": [ 24 | "off" 25 | ], 26 | "global-require": [ 27 | "warn" 28 | ], 29 | "no-underscore-dangle": [ 30 | "off" 31 | ], 32 | "no-case-declarations": [ 33 | "warn" 34 | ], 35 | "max-len": [ 36 | "warn", 37 | 120, 38 | { 39 | "ignoreUrls": true 40 | } 41 | ], 42 | "no-unused-vars": [ 43 | "warn" 44 | ], 45 | "no-nested-ternary": [ 46 | "warn" 47 | ], 48 | "no-class-assign": [ 49 | "off" 50 | ], 51 | "no-use-before-define": [ 52 | "error", 53 | { 54 | "functions": false, 55 | "classes": true 56 | } 57 | ], 58 | "new-cap": [ 59 | "error", 60 | { 61 | "capIsNewExceptions": [ 62 | "List", 63 | "Map", 64 | "OrderedMap", 65 | "Set", 66 | "OrderedSet", 67 | "Stack", 68 | "Range", 69 | "Repeat", 70 | "Record", 71 | "Seq" 72 | ] 73 | } 74 | ], 75 | "linebreak-style": [ 76 | "off" 77 | ], 78 | "import/prefer-default-export": [ 79 | "off" 80 | ], 81 | "react/prefer-stateless-function": [ 82 | "off" 83 | ], 84 | "react/jsx-curly-spacing": [ 85 | "off" 86 | ], 87 | "react/forbid-prop-types": [ 88 | "off" 89 | ], 90 | "react/no-unused-prop-types": [ 91 | "warn" 92 | ] 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /examples/reactapp/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # plan text 4 | *.txt text 5 | *.java text 6 | *.scala text 7 | *.groovy text 8 | *.gradle text 9 | *.xml text 10 | *.xsd text 11 | *.tld text 12 | *.yaml text 13 | *.yml text 14 | *.wsdd text 15 | *.wsdl text 16 | *.jsp text 17 | *.jspf text 18 | *.js text 19 | *.jsx text 20 | *.json text 21 | *.css text 22 | *.less text 23 | *.sql text 24 | *.properties text 25 | 26 | # unix style 27 | *.sh text eol=lf 28 | 29 | # win style 30 | *.bat text eol=crlf 31 | 32 | # don't handle 33 | *.der -text 34 | *.jks -text 35 | *.pfx -text 36 | *.map -text 37 | *.patch -text 38 | *.dat -text 39 | *.data -text 40 | *.db -text 41 | 42 | # binary 43 | *.jar binary 44 | *.war binary 45 | *.zip binary 46 | *.tar binary 47 | *.tar.gz binary 48 | *.gz binary 49 | *.apk binary 50 | *.bin binary 51 | *.exe binary 52 | 53 | # 图片 54 | *.png binary 55 | *.jpg binary 56 | *.ico binary 57 | *.gif binary 58 | 59 | # 音视频 60 | *.mp3 binary 61 | *.swf binary 62 | 63 | # other doc 64 | *.pdf binary 65 | *.doc binary 66 | *.docx binary 67 | *.xls binary 68 | *.xlsx binary 69 | -------------------------------------------------------------------------------- /examples/reactapp/.gitignore: -------------------------------------------------------------------------------- 1 | # project 2 | node_modules 3 | 4 | # build 5 | dist/ 6 | coverage 7 | 8 | # IDE files 9 | .idea/ 10 | *.iml 11 | .ipr 12 | .iws 13 | 14 | # temp and sys 15 | *~ 16 | ~* 17 | *.diff 18 | *.patch 19 | *.bak 20 | .DS_Store 21 | Thumbs.db 22 | *.log 23 | 24 | # other 25 | .project 26 | .*proj 27 | .svn/ 28 | *.swp 29 | *.swo 30 | *.pyc 31 | *.pyo 32 | -------------------------------------------------------------------------------- /examples/reactapp/config/app.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file app 的全局配置 3 | * @author Zhang Peng 4 | */ 5 | 6 | module.exports = { 7 | 8 | /** 9 | * 打印日志开关 10 | */ 11 | log: true, 12 | 13 | http: { 14 | 15 | /** 16 | * 请求超时时间 17 | */ 18 | timeout: 5000, 19 | 20 | /** 21 | * 服务器的host 22 | */ 23 | baseURL: '/api' 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/reactapp/config/webpack.config.base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhang Peng on 2017/6/14. 3 | */ 4 | const path = require('path') 5 | const webpack = require('webpack') 6 | const HtmlWebpackPlugin = require('html-webpack-plugin') 7 | 8 | 9 | module.exports = { 10 | 11 | // 这里应用程序开始执行 12 | // webpack 开始打包 13 | // 本例中 entry 为多入口 14 | entry: { 15 | // 第三方库 16 | vendor: ['babel-polyfill'] 17 | }, 18 | 19 | // webpack 如何输出结果的相关选项 20 | output: { 21 | // 所有输出文件的目标路径 22 | // 必须是绝对路径(使用 Node.js 的 path 模块) 23 | path: path.resolve(__dirname, '../dist'), 24 | 25 | // 「入口分块(entry chunk)」的文件名模板(出口分块?) 26 | // filename: "bundle.min.js", 27 | // filename: "[name].js", // 用于多个入口点(entry point)(出口点?) 28 | // filename: "[chunkhash].js", // 用于长效缓存 29 | filename: '[name].[hash:8].js', 30 | 31 | // 「source map 位置」的文件名模板 32 | sourceMapFilename: '[name].map' 33 | }, 34 | 35 | // 关于模块配置 36 | module: { 37 | 38 | // 模块规则(配置 loader、解析器等选项) 39 | rules: [ 40 | // 这里是匹配条件,每个选项都接收一个正则表达式或字符串 41 | // test 和 include 具有相同的作用,都是必须匹配选项 42 | // exclude 是必不匹配选项(优先于 test 和 include) 43 | // 最佳实践: 44 | // - 只在 test 和 文件名匹配 中使用正则表达式 45 | // - 在 include 和 exclude 中使用绝对路径数组 46 | // - 尽量避免 exclude,更倾向于使用 include 47 | { 48 | // 语义解释器,将 js/jsx 文件中的 es2015/react 语法自动转为浏览器可识别的 Javascript 语法 49 | test: /\.jsx?$/, 50 | include: path.resolve(__dirname, '../src'), 51 | exclude: /node_modules/, 52 | 53 | // 应该应用的 loader,它相对上下文解析 54 | // 为了更清晰,`-loader` 后缀在 webpack 2 中不再是可选的 55 | // 查看 webpack 1 升级指南。 56 | loader: 'babel-loader' 57 | }, 58 | 59 | { 60 | // css 加载 61 | test: /\.css$/, 62 | use: ['style-loader', 'css-loader'] 63 | }, 64 | 65 | { 66 | // less 加载 67 | test: /\.less$/, 68 | use: ['style-loader', 'css-loader', 'less-loader'] 69 | }, 70 | 71 | { 72 | // 字体加载 73 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 74 | loader: 'url-loader', 75 | options: { 76 | limit: 10000, 77 | name: 'static/fonts/[name].[hash:8].[ext]' 78 | } 79 | } 80 | ] 81 | }, 82 | 83 | // 解析模块请求的选项 84 | // (不适用于对 loader 解析) 85 | resolve: { 86 | // 使用的扩展名 87 | extensions: ['.js', '.jsx', '.json'], 88 | 89 | alias: { 90 | '@': path.resolve(__dirname, '../src') 91 | } 92 | }, 93 | 94 | // 附加插件列表 95 | plugins: [ 96 | 97 | /** 98 | * https://doc.webpack-china.org/plugins/html-webpack-plugin/ 99 | * 用于简化 HTML 文件(index.html)的创建,提供访问 bundle 的服务 100 | */ 101 | new HtmlWebpackPlugin({ 102 | title: 'reactapp', 103 | template: 'public/index.html', 104 | favicon: 'public/favicon.ico' 105 | }), 106 | 107 | 108 | // 将多个入口起点之间共享的公共模块,生成为一些 chunk,并且分离到单独的 bundle 中 109 | new webpack.optimize.CommonsChunkPlugin({ 110 | name: 'vendor' // 指定公共 bundle 的名字 111 | }) 112 | ] 113 | } 114 | -------------------------------------------------------------------------------- /examples/reactapp/config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhang Peng on 2017/6/14. 3 | */ 4 | const path = require('path') 5 | const webpack = require('webpack') 6 | const webpackMerge = require('webpack-merge') 7 | const OpenBrowserPlugin = require('open-browser-webpack-plugin') 8 | const baseWebpackConfig = require('./webpack.config.base') 9 | 10 | module.exports = webpackMerge(baseWebpackConfig, { 11 | // 这里应用程序开始执行 12 | // webpack 开始打包 13 | // 本例中 entry 为多入口 14 | entry: { 15 | main: [ 16 | // App 入口 17 | path.resolve(__dirname, '../src/index'), 18 | 19 | // 开启 React 代码的模块热替换(HMR) 20 | 'react-hot-loader/patch', 21 | 22 | // 为 webpack-dev-server 的环境打包代码 23 | // 然后连接到指定服务器域名与端口 24 | 'webpack-dev-server/client?http://localhost:9000', 25 | 26 | // 为热替换(HMR)打包好代码 27 | // only- 意味着只有成功更新运行代码才会执行热替换(HMR) 28 | 'webpack/hot/only-dev-server' 29 | ] 30 | }, 31 | 32 | output: { 33 | // 对于热替换(HMR)是必须的,让 webpack 知道在哪里载入热更新的模块(chunk) 34 | publicPath: '/' 35 | }, 36 | 37 | // 关于模块配置 38 | module: { 39 | 40 | // 模块规则(配置 loader、解析器等选项) 41 | rules: [ 42 | 43 | { 44 | // 图片加载 + 图片压缩 45 | test: /\.(png|svg|jpg|gif|ico)$/, 46 | loader: 'url-loader', 47 | options: { 48 | limit: 10000, 49 | name: 'static/images/[name].[hash:8].[ext]' 50 | } 51 | } 52 | ] 53 | }, 54 | 55 | // 附加插件列表 56 | plugins: [ 57 | 58 | // 定义环境变量 59 | new webpack.DefinePlugin({ 60 | 'process.env.NODE_ENV': JSON.stringify('development') 61 | }), 62 | 63 | // 开启全局的模块热替换(HMR) 64 | new webpack.HotModuleReplacementPlugin(), 65 | 66 | // 当模块热替换(HMR)时在浏览器控制台输出对用户更友好的模块名字信息 67 | new webpack.NamedModulesPlugin(), 68 | 69 | // 自动打开浏览器 70 | new OpenBrowserPlugin({ 71 | url: 'http://localhost:9000' 72 | }) 73 | ], 74 | 75 | // 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试 76 | // devtool: "source-map", // 牺牲了构建速度的 `source-map' 是最详细的 77 | // devtool: "inline-source-map", // 嵌入到源文件中 78 | // devtool: "eval-source-map", // 将 SourceMap 嵌入到每个模块中 79 | // devtool: "hidden-source-map", // SourceMap 不在源文件中引用 80 | // devtool: "cheap-source-map", // 没有模块映射(module mappings)的 SourceMap 低级变体(cheap-variant) 81 | devtool: 'eval-source-map', // 有模块映射(module mappings)的 SourceMap 低级变体 82 | // devtool: "eval", // 没有模块映射,而是命名模块。以牺牲细节达到最快。 83 | 84 | devServer: { 85 | contentBase: [path.join(__dirname, '../dist')], 86 | compress: true, 87 | port: 9000, // 启动端口号 88 | hot: true, // 启用 webpack 的模块热替换特性 89 | inline: true, 90 | publicPath: '/', // 和上文 output 的“publicPath”值保持一致 91 | historyApiFallback: true 92 | } 93 | }) 94 | -------------------------------------------------------------------------------- /examples/reactapp/config/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zhang Peng on 2017/6/14. 3 | */ 4 | const path = require('path') 5 | const webpack = require('webpack') 6 | const webpackMerge = require('webpack-merge') 7 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | const baseWebpackConfig = require('./webpack.config.base') 9 | 10 | module.exports = webpackMerge(baseWebpackConfig, { 11 | // 这里应用程序开始执行 12 | // webpack 开始打包 13 | // 本例中 entry 为多入口 14 | entry: { 15 | main: [ 16 | // App 入口 17 | path.resolve(__dirname, '../src/index') 18 | ] 19 | }, 20 | 21 | // 关于模块配置 22 | module: { 23 | 24 | // 模块规则(配置 loader、解析器等选项) 25 | rules: [ 26 | { 27 | // 图片加载 + 图片压缩 28 | test: /\.(png|svg|jpg|gif|ico)$/, 29 | loaders: [ 30 | { 31 | loader: 'url-loader', 32 | options: { 33 | limit: 10000, 34 | name: 'static/images/[name].[hash:8].[ext]' 35 | } 36 | }, 37 | 38 | { 39 | loader: 'image-webpack-loader', 40 | query: { 41 | progressive: true, 42 | pngquant: { 43 | quality: '65-90', 44 | speed: 4 45 | } 46 | } 47 | } 48 | 49 | ] 50 | } 51 | ] 52 | }, 53 | 54 | // 附加插件列表 55 | plugins: [ 56 | 57 | // 定义环境变量 58 | new webpack.DefinePlugin({ 59 | 'process.env.NODE_ENV': JSON.stringify('production') 60 | }), 61 | 62 | // 加载选项插件 63 | new webpack.LoaderOptionsPlugin({ 64 | minimize: true, 65 | debug: false 66 | }), 67 | 68 | // 压缩 js 插件 69 | new webpack.optimize.UglifyJsPlugin({ 70 | output: { 71 | comments: false // remove all comments 72 | }, 73 | compress: { 74 | warnings: false 75 | } 76 | }), 77 | 78 | // 将样式文件独立打包 79 | new ExtractTextPlugin('styles.css') 80 | ] 81 | }) 82 | -------------------------------------------------------------------------------- /examples/reactapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactapp", 3 | "version": "0.0.1", 4 | "description": "reactapp", 5 | "main": "index.js", 6 | "scripts": { 7 | "clean": "rimraf ./dist", 8 | "lint": "eslint --ext .js,.jsx src", 9 | "dev": "webpack-dev-server --config config/webpack.config.dev.js --color", 10 | "prod": "npm run clean && webpack --config config/webpack.config.prod.js --color", 11 | "start": "if-env NODE_ENV=production && npm run prod || npm run dev" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/dunwu/react-admin.git" 16 | }, 17 | "author": "Zhang Peng", 18 | "license": "MIT", 19 | "engines": { 20 | "node": ">= 4.0.0", 21 | "npm": ">= 3.0.0" 22 | }, 23 | "dependencies": { 24 | "antd": "^2.12.1", 25 | "axios": "^0.19.0", 26 | "isomorphic-fetch": "^2.2.1", 27 | "less": "^2.7.1", 28 | "lodash": "^4.16.4", 29 | "moment": "^2.18.1", 30 | "prop-types": "^15.5.10", 31 | "react": "^15.6.1", 32 | "react-dom": "^15.6.1", 33 | "react-redux": "^5.0.0", 34 | "react-router": "^4.1.0", 35 | "react-router-dom": "^4.1.1", 36 | "redux": "^3.7.2", 37 | "redux-thunk": "^2.2.0", 38 | "reqwest": "^2.0.5" 39 | }, 40 | "devDependencies": { 41 | "axios-mock-adapter": "^1.7.1", 42 | "babel-core": "^6.25.0", 43 | "babel-loader": "^7.1.0", 44 | "babel-plugin-import": "^1.2.1", 45 | "babel-plugin-syntax-dynamic-import": "^6.18.0", 46 | "babel-plugin-transform-runtime": "^6.15.0", 47 | "babel-polyfill": "^6.23.0", 48 | "babel-preset-env": "^1.5.2", 49 | "babel-preset-react": "^6.24.1", 50 | "babel-preset-stage-0": "^6.24.1", 51 | "css-loader": "^0.25.0", 52 | "eslint": "3.7.1", 53 | "eslint-config-airbnb": "12.0.0", 54 | "eslint-plugin-import": "1.16.0", 55 | "eslint-plugin-jsx-a11y": "2.2.3", 56 | "eslint-plugin-react": "6.3.0", 57 | "extract-text-webpack-plugin": "^2.1.2", 58 | "file-loader": "^0.9.0", 59 | "html-webpack-plugin": "^2.24.1", 60 | "if-env": "^1.0.0", 61 | "image-webpack-loader": "^3.3.1", 62 | "less-loader": "^2.2.3", 63 | "open-browser-webpack-plugin": "^0.0.5", 64 | "react-hot-loader": "^3.0.0-beta.7", 65 | "redux-devtools": "^3.4.0", 66 | "redux-devtools-dock-monitor": "^1.0.1", 67 | "redux-devtools-log-monitor": "^1.0.2", 68 | "redux-logger": "^3.0.6", 69 | "redux-mock-store": "^1.2.3", 70 | "rimraf": "^2.6.1", 71 | "style-loader": "^0.18.2", 72 | "url-loader": "^0.5.7", 73 | "webpack": "^3.5.5", 74 | "webpack-dev-server": "^2.7.1", 75 | "webpack-merge": "^4.1.0" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /examples/reactapp/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunwu/nginx-tutorial/452bc2d0d3b74d0d40cab700cab278a9b6bc5f2a/examples/reactapp/public/favicon.ico -------------------------------------------------------------------------------- /examples/reactapp/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= htmlWebpackPlugin.options.title %> 5 | 6 | 7 | 8 | 9 | 10 |
11 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/reactapp/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ln -s /app/ck-puck-front/node_modules/ node_modules 4 | nvm use 8.1.0 5 | npm set registry http://192.168.51.44 6 | npm install 7 | npm run build 8 | rm -rf /app/ck-puck-front/dist 9 | mkdir -p /app/ck-puck-front/dist 10 | cp -Rf ./dist /app/ck-puck-front/ 11 | -------------------------------------------------------------------------------- /examples/reactapp/src/common/apiutils/ajaxCommon.js: -------------------------------------------------------------------------------- 1 | import { Modal } from 'antd' 2 | import _ from 'lodash' 3 | 4 | import { COMMON_REQUEST_ERROR } from '../../redux/constants/commonActionTypes' 5 | 6 | export const REQ_BASE_URL = '/api' 7 | 8 | export const METHODS = { 9 | GET: 'GET', 10 | HEAD: 'HEAD', 11 | POST: 'POST', 12 | PUT: 'PUT', 13 | DEL: 'DEL', 14 | OPTIONS: 'OPTIONS', 15 | PATCH: 'PATCH' 16 | } 17 | 18 | export const REQ_TYPE = { 19 | HTML: 'html', 20 | JSON: 'json', 21 | JSONP: 'jsonp' 22 | } 23 | 24 | export const CACHE_TYPE = { 25 | DEFAULT: 'default', 26 | NO_STORE: 'no-store', 27 | RELOAD: 'reload', 28 | NO_CACHE: 'no-cache', 29 | FORCE_CACHE: 'force-cache' 30 | } 31 | 32 | export const ERROR_HANDLER_TYPE = { 33 | NO: 'NO', // ['NO' | undefined | false ] 不处理 34 | SYSTEM: 'SYSTEM', // ['SYSTEM'] 只处理系统预料外的返回(not json) 35 | SYSTEM_AND_AUTH: 'SYSTEM_AND_AUTH', // [true, 'SYSTEM_AND_AUTH'] 处理上一步,与 认证失败 (比较常用,所以单独列出,用true) 36 | ALL: 'ALL' // [no errorHandler | 'ALL'] 所有 37 | } 38 | 39 | export const defaultOptions = { 40 | url: null, 41 | method: METHODS.GET, 42 | headers: {}, 43 | data: null, 44 | type: null, 45 | contentType: null, 46 | crossOrigin: null, 47 | onSuccess: () => { 48 | }, 49 | onError: () => { 50 | }, 51 | cache: CACHE_TYPE.NO_CACHE 52 | } 53 | 54 | // 在 defaultOptions 基础上多出来的, request plan text,response json 55 | export const defaultJsonOptions = _.merge({}, defaultOptions, { 56 | headers: { 57 | Accept: 'application/json, text/plain, */*', 58 | 'Cache-Control': 'no-cache' 59 | }, 60 | type: REQ_TYPE.JSON 61 | }) 62 | 63 | // 在 defaultJsonOptions 基础上多出来的, request response 皆是 json 64 | export const defaultBiJsonOptions = _.merge({}, defaultJsonOptions, { 65 | headers: { 66 | 'Content-Type': 'application/json;charset=UTF-8' 67 | }, 68 | reqType: REQ_TYPE.JSON 69 | }) 70 | 71 | // 获取真正请求的 URL 72 | export function getRealUrl(url) { 73 | if (!!url && !url.startsWith('http')) { 74 | return REQ_BASE_URL + url 75 | } 76 | return url 77 | } 78 | 79 | /** 80 | * 展示认证错误 81 | * @private 82 | */ 83 | function _showAuthError() { 84 | Modal.error({ 85 | title: '认证失败', 86 | // eslint-disable-next-line react/jsx-filename-extension 87 | content: ( < p > 您现在处于非认证状态!!!< 88 | br / > 89 | 如果想保留本页状态,请在 < a 90 | href = '/login' 91 | target = 'blank' > 新页面登陆 < /a> 。
92 | { /* 否则在 当前页登陆 。 */ } 93 | < /p>), 94 | }) 95 | 96 | } 97 | 98 | /** 99 | * 防抖展示认证错误(一段时间内仅一次) 100 | * @type {Function} 101 | */ 102 | const showAuthError = _.debounce(_showAuthError, 500, { 103 | leading: true, 104 | trailing: false 105 | }) 106 | 107 | /** 108 | * 展示服务端错误信息 109 | * @param e 110 | */ 111 | function _showServerError(e) { 112 | Modal.error({ 113 | title: '服务端错误!', 114 | content: `服务端错误。服务端可能未正确部署或由于其他原因响应失败!请保留现场并联系开发人员。错误信息: ${e}` 115 | }) 116 | } 117 | 118 | /** 119 | * 防抖展示服务端错误(一段时间内仅一次) 120 | * @type {Function} 121 | */ 122 | const showServerError = _.debounce(_showServerError, 500, { 123 | leading: true, 124 | trailing: false 125 | }) 126 | 127 | /** 128 | * 包装错误处理。所有服务端应用(非业务)非 ret 预计错误与认证错误统一处理。 129 | * 其他根据情况,如果未传入错误处理函数或错误处理函数返回 true,则接管处理。 130 | * 用于处理 api 请求未传入错误处理函数的情况。
131 | * 如果传入 dispatch,则会 dispatch 公共 action。
132 | * 如果无 dispatch,则 console.log error 133 | * @param errorHandler 134 | * @param dispatch 135 | * @returns {function()} 136 | */ 137 | export function wrapErrorHandler(errorHandler, dispatch) { 138 | return (e) => { 139 | let handlerLevel = 1000 // 默认都处理 140 | // 先看是否传入 errorHandler,如果传入,则执行用户 errorHandler,并根据处理结果设置新的 handlerLevel 141 | if (_.isFunction(errorHandler)) { 142 | handlerLevel = _getErrorHandlerLevel(errorHandler(e)) 143 | } 144 | 145 | if (handlerLevel > 0 && e instanceof XMLHttpRequest) { 146 | // 服务端应用(非业务)非 ret 预计错误处理,如 404,400,500,非返回 json 错误 147 | showServerError(e.responseText) 148 | } else if (handlerLevel > 10 && e.ret === -1) { 149 | // 认证失败,该登陆未登录 150 | showAuthError() 151 | } else if (handlerLevel > 100 && dispatch) { 152 | dispatch({ type: COMMON_REQUEST_ERROR, payload: e }) 153 | } else if (handlerLevel > 100) { 154 | const msg = e.ret ? `[code]${e.ret}, [msg]${e.msg}` : JSON.stringify(e) 155 | // eslint-disable-next-line no-console 156 | console.error(`请求出错: ${msg}`) 157 | } 158 | } 159 | } 160 | 161 | function _getErrorHandlerLevel(type) { 162 | if (type === ERROR_HANDLER_TYPE.SYSTEM) { 163 | return 10 164 | } else if (type === ERROR_HANDLER_TYPE.SYSTEM_AND_AUTH || type === true) { 165 | return 100 166 | } else if (type === ERROR_HANDLER_TYPE.ALL) { 167 | return 1000 168 | } 169 | return 0 170 | } 171 | -------------------------------------------------------------------------------- /examples/reactapp/src/common/apiutils/apiCreator.js: -------------------------------------------------------------------------------- 1 | const createApi = fetchFunc => options => (...args) => { 2 | let finalOpts 3 | const argsName = ['options', 'successCallBack', 'errorCallBack', 'dispatch'] 4 | // options 可以是 url,或完整的 options 对象 5 | if (typeof options === 'string') { 6 | finalOpts = { url: options } 7 | } else { 8 | finalOpts = { ...options } 9 | } 10 | 11 | const temArgs = {} 12 | if (args) { 13 | // args 第一个参数,options 可以忽略 14 | let i = 0 15 | if (args[0] !== null && typeof args[0] === 'object') { 16 | i = 1 17 | finalOpts = Object.assign(finalOpts, args[0]) 18 | } 19 | 20 | // eslint-disable-next-line no-plusplus 21 | for (let j = i; j < args.length; j++) { 22 | // eslint-disable-next-line no-mixed-operators 23 | temArgs[argsName[j - i + 1]] = args[j] 24 | } 25 | } 26 | 27 | if (temArgs.successCallBack) { 28 | finalOpts.onSuccess = temArgs.successCallBack 29 | } 30 | 31 | if (temArgs.errorCallBack) { 32 | finalOpts.onError = temArgs.errorCallBack 33 | } 34 | fetchFunc(finalOpts, temArgs.dispatch) 35 | } 36 | 37 | export default createApi 38 | -------------------------------------------------------------------------------- /examples/reactapp/src/common/apiutils/errorUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 错误处理帮助类 3 | */ 4 | import { Message } from 'antd' 5 | import _ from 'lodash' 6 | 7 | import { ERROR_HANDLER_TYPE } from './index' 8 | 9 | /** 10 | * 处理业务类型的错误(-3),通过 message 的方式展现 11 | * @param e 12 | * @param callBack 13 | * @return {boolean} 14 | */ 15 | export function messageBizError(e, callBack) { 16 | let continueHandler = true 17 | if (e && e.ret === -3) { 18 | // 业务错误 19 | Message.error(e.msg, 4.5) 20 | continueHandler = ERROR_HANDLER_TYPE.NO 21 | } 22 | if (_.isFunction(callBack)) { 23 | callBack({ error: e }) 24 | } 25 | return continueHandler 26 | } 27 | -------------------------------------------------------------------------------- /examples/reactapp/src/common/apiutils/fetchAJAX.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import { defaultJsonOptions, defaultOptions, getRealUrl, REQ_TYPE, wrapErrorHandler } from './ajaxCommon' 3 | 4 | function handleStatus(res) { 5 | if (res.ok) { 6 | return res 7 | } 8 | throw new Error({ result: res.status }) 9 | } 10 | 11 | // json 有固定的格式,所以固定处理方法 12 | function handleJson(data) { 13 | // noinspection JSUnresolvedVariable 14 | if (data.ret === 0) { 15 | return data.data 16 | } 17 | throw new Error(data) 18 | } 19 | 20 | export function doFetch(options = {}, dispatch) { 21 | const opts = { 22 | ...defaultOptions, 23 | ...options, 24 | onError: wrapErrorHandler(options.onError, dispatch) 25 | } 26 | 27 | // 根据配置创建 Request 对象 28 | const req = new Request(getRealUrl(opts.url), { 29 | method: opts.method, 30 | headers: opts.headers, 31 | body: opts.data, 32 | cache: opts.cache, 33 | redirect: 'follow', 34 | mode: 'cors' 35 | }) 36 | 37 | if (!__DEV__) { 38 | req.credentials = 'include' 39 | } 40 | 41 | // 请求 42 | // FIXME 应该根据 response 类型自动判断是否 Json 请求 43 | let tempRes = fetch(req).then(handleStatus) 44 | if (options.type === REQ_TYPE.JSON) { 45 | tempRes = tempRes.then(res => res.json()).then(handleJson) 46 | } 47 | tempRes.then(options.onSuccess).catch(options.onError) 48 | } 49 | 50 | export function doFetchJson(options = {}, dispatch) { 51 | const opts = { ...defaultJsonOptions, ...options } 52 | doFetch(opts, dispatch) 53 | } 54 | -------------------------------------------------------------------------------- /examples/reactapp/src/common/apiutils/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * export 一个 API,底层的实现可能会改(如,切换为 reqwest/superagent/fetch) 3 | */ 4 | import { CACHE_TYPE, ERROR_HANDLER_TYPE, METHODS, REQ_TYPE } from './ajaxCommon' 5 | import { doBiJsonFetch, doFetch, doFetchJson } from './reqwestAJAX' 6 | import createApi from './apiCreator' 7 | 8 | /** 9 | * 创建一个 API 函数,结果可以是任何形式。如果是响应是 JSON 会自动转换,类似于 #createFetchJson 结果。
10 | * 但是,请求头不指名 Json : Accept:text/javascript, text/html, application/xml, text/xml, *\/* 11 | */ 12 | const createFetch = createApi(doFetch) 13 | 14 | /** 15 | * 创建一个 API 函数,明确指明函数用于获取 Json 格式数据。如果结果不符合格式会转到错误处理
16 | * 请求头:Accept:application/json, text/plain, *\/* 17 | */ 18 | const createFetchJson = createApi(doFetchJson) 19 | 20 | // 创建一个 API 函数, 指明客户端、服务端 内容体(content body)都是 Json 格式。
21 | // 在 #createFetchJson 的基础上添加:Content-Type: application/json;charset=UTF-8,
22 | // 同时,如果请求 data 为 Object类型会通过 JSON.stringify 转换 23 | const createBiJsonFetch = createApi(doBiJsonFetch) 24 | 25 | /** 26 | * 将 api 转换为返回 Promise 方式, 不处理 error。 如果处理 error, 请君自new 27 | * @private 28 | */ 29 | const createPromiseAPI = api => (data) => { 30 | return new Promise((resolve) => { 31 | api({ data }, rs => resolve(rs)) 32 | }) 33 | } 34 | 35 | const API = { 36 | METHODS, 37 | REQ_TYPE, 38 | CACHE_TYPE, 39 | ERROR_HANDLER_TYPE, 40 | doFetch, 41 | doFetchJson, 42 | createFetch, 43 | createFetchJson, 44 | createBiJsonFetch, 45 | createPromiseAPI 46 | } 47 | 48 | export default API 49 | -------------------------------------------------------------------------------- /examples/reactapp/src/common/apiutils/reqwestAJAX.js: -------------------------------------------------------------------------------- 1 | import reqwest from 'reqwest' 2 | import _ from 'lodash' 3 | import { 4 | defaultBiJsonOptions, 5 | defaultJsonOptions, 6 | defaultOptions, 7 | getRealUrl, 8 | METHODS, 9 | REQ_TYPE, 10 | wrapErrorHandler 11 | } from './ajaxCommon' 12 | 13 | function _doFetch(options = {}, dispatch, defaultMergeOption = {}) { 14 | const opts = _.merge({}, defaultMergeOption, options, { 15 | url: getRealUrl(options.url), 16 | error: wrapErrorHandler(options.onError, dispatch) 17 | }) 18 | 19 | const method = opts.method && opts.method.toUpperCase() 20 | const data = opts.data 21 | if (METHODS.GET === method && opts.processData !== false && !_.isString(data)) { 22 | // get 请求,配置 processData 不为否,data 不为 String 则预处理 23 | const newData = { ...data, ts: new Date().getTime() } // 加入时间戳,防止浏览器缓存 24 | opts.data = reqwest.toQueryString(newData, true) // traditional 方式,保证数组符合 spring mvc 的传参方式。 25 | } 26 | 27 | opts.success = (res) => { 28 | const doSuc = options.onSuccess ? options.onSuccess : defaultOptions.onSuccess // reqwest 名字不同 29 | if (opts.type === REQ_TYPE.JSON || typeof res === 'object') { 30 | // noinspection JSUnresolvedVariable 31 | if (res.result === 0 || res.ret === 0) { 32 | doSuc(res.data) 33 | } else { 34 | opts.error(res) 35 | } 36 | } else { 37 | doSuc(res) 38 | } 39 | } 40 | 41 | reqwest(opts) 42 | } 43 | 44 | export function doFetch(options = {}, dispatch) { 45 | _doFetch(options, dispatch, defaultOptions) 46 | } 47 | 48 | export function doFetchJson(options = {}, dispatch) { 49 | _doFetch(options, dispatch, defaultJsonOptions) 50 | } 51 | 52 | export function doBiJsonFetch(options = {}, dispatch) { 53 | let opts = options 54 | if (typeof opts.data === 'object') { 55 | opts = { ...options, data: JSON.stringify(opts.data) } 56 | } 57 | _doFetch(opts, dispatch, defaultBiJsonOptions) 58 | } 59 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 本项目二次封装的 UI 组件入口 3 | * @author Zhang Peng 4 | */ 5 | 6 | /****************************** 布局组件 ******************************/ 7 | export { default as Header } from './layout/Header/Header' 8 | export { default as Sidebar } from './layout/Sidebar/Sidebar' 9 | export { default as Content } from './layout/Content/Content' 10 | export { default as Footer } from './layout/Footer/Footer' 11 | export { default as Breadcrumb } from './layout/Breadcrumb/Breadcrumb' 12 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Breadcrumb/Breadcrumb.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 面包屑组件 3 | * @author Zhang Peng 4 | * @see https://github.com/facebook/prop-types 5 | * @see https://ant.design/components/breadcrumb-cn/ 6 | * @see https://ant.design/components/icon-cn/ 7 | */ 8 | import { Breadcrumb, Icon } from 'antd' 9 | import PropTypes from 'prop-types' 10 | import React from 'react' 11 | import './Breadcrumb.less' 12 | 13 | /** 14 | * 面包屑组件 15 | * @class 16 | */ 17 | class CustomBreadcrumb extends React.PureComponent { 18 | static propTypes = { 19 | data: PropTypes.array 20 | } 21 | 22 | static defaultProps = { 23 | data: [] 24 | } 25 | 26 | render() { 27 | const { data } = this.props 28 | const breadcrumbItems = data.map((item) => { 29 | return ( 30 | 31 | 32 | {item.title} 33 | 34 | ) 35 | }) 36 | 37 | return ( 38 |
39 | 40 | 41 | 42 | Home 43 | 44 | {breadcrumbItems} 45 | 46 |
47 | ) 48 | } 49 | } 50 | 51 | export default CustomBreadcrumb 52 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Breadcrumb/Breadcrumb.less: -------------------------------------------------------------------------------- 1 | .ant-layout-breadcrumb { 2 | z-index: 200; 3 | line-height: 64px; 4 | 5 | .ant-breadcrumb-link { 6 | font-size: 16px; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Content/Content.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 内容布局组件 3 | * @author Zhang Peng 4 | * @see https://ant.design/components/layout-cn/ 5 | * @see https://ant.design/components/card-cn/ 6 | */ 7 | import { Card, Layout } from 'antd' 8 | import React from 'react' 9 | 10 | import './Content.less' 11 | 12 | const { Content } = Layout 13 | 14 | /** 15 | * 内容布局组件 16 | * @class 17 | */ 18 | class CustomContent extends React.PureComponent { 19 | constructor(props) { 20 | super(props) 21 | } 22 | 23 | render() { 24 | return ( 25 | 26 | 27 | {this.props.children} 28 | 29 | 30 | ) 31 | } 32 | } 33 | 34 | export default CustomContent 35 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Content/Content.less: -------------------------------------------------------------------------------- 1 | .ant-layout-content { 2 | background: #fff; 3 | padding: 24px; 4 | } 5 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 底部布局组件 3 | * @author Zhang Peng 4 | * @see https://ant.design/components/layout-cn/ 5 | */ 6 | import { Layout } from 'antd' 7 | import React from 'react' 8 | 9 | import './index.less' 10 | 11 | const { Footer } = Layout 12 | 13 | /** 14 | * 底部布局组件 15 | * @class 16 | */ 17 | class CustomFooter extends React.PureComponent { 18 | render() { 19 | return ( 20 |
21 | Ant Admin © 2017-2018 https://github.com/dunwu 22 |
23 | ) 24 | } 25 | } 26 | 27 | export default CustomFooter 28 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Footer/index.less: -------------------------------------------------------------------------------- 1 | .ant-layout-footer { 2 | height: 64px; 3 | line-height: 32px; 4 | text-align: center; 5 | font-size: 14px; 6 | color: #999; 7 | background: #fff; 8 | border-top: 1px solid #e9e9e9; 9 | width: 100%; 10 | } 11 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Header/Header.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 顶部布局组件 3 | * @author Zhang Peng 4 | * @see https://ant.design/components/layout-cn/ 5 | */ 6 | import { Avatar, Badge, Col, Dropdown, Icon, Layout, Menu, Popover, Row } from 'antd' 7 | import React from 'react' 8 | import { Link, withRouter } from 'react-router-dom' 9 | import PropTypes from 'prop-types' 10 | import { connect } from 'react-redux' 11 | import { bindActionCreators } from 'redux' 12 | 13 | import './Header.less' 14 | import Breadcrumb from '../Breadcrumb/Breadcrumb' 15 | import { fetchProfile, logout } from '../../../redux/actions/auth' 16 | 17 | const { Header } = Layout 18 | 19 | const content = ( 20 |
21 |

Content

22 |

Content

23 |

Content

24 |

Content

25 |

Content

26 |
27 | ) 28 | 29 | const mapStateToProps = (state) => { 30 | const { auth, menu } = state 31 | return { 32 | auth: auth ? auth : null, 33 | navpath: menu.navpath 34 | } 35 | } 36 | 37 | const mapDispatchToProps = (dispatch) => { 38 | return { actions: bindActionCreators({ fetchProfile, logout }, dispatch) } 39 | } 40 | 41 | /** 42 | * 顶部布局组件 43 | * @class 44 | */ 45 | class CustomHeader extends React.PureComponent { 46 | static propTypes = { 47 | auth: PropTypes.object, 48 | actions: PropTypes.object, 49 | navpath: PropTypes.array 50 | } 51 | static defaultProps = { 52 | auth: null, 53 | actions: null, 54 | navpath: [] 55 | } 56 | 57 | componentWillMount() { 58 | const { actions } = this.props 59 | actions.fetchProfile() 60 | } 61 | 62 | handleLogOut = () => { 63 | const { actions } = this.props 64 | actions.logout().payload.promise.then(() => { 65 | this.props.history.replace('/login') 66 | }) 67 | } 68 | 69 | render() { 70 | const { auth, navpath } = this.props 71 | let username = '' 72 | if (auth.user) { 73 | if (auth.user.data) { 74 | username = auth.user.data.name 75 | } 76 | } 77 | 78 | const menu = ( 79 | 80 | 81 | 选项1 82 | 83 | 84 | 选项2 85 | 86 | 87 | 88 | 注销 89 | 90 | 91 | ) 92 | 93 | return ( 94 |
95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | {username} 117 | 118 | 119 | 120 | 121 | 122 | 123 |
124 | ) 125 | } 126 | } 127 | 128 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CustomHeader)) 129 | 130 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Header/Header.less: -------------------------------------------------------------------------------- 1 | .ant-layout-header { 2 | top: 0; 3 | right: 0; 4 | //height: 64px; 5 | //padding: 25px; 6 | z-index: 150; 7 | background: #fff; 8 | box-shadow: 0 0 1px 0 rgba(0, 0, 0, .3), 0 0 6px 2px rgba(0, 0, 0, .15); 9 | } 10 | 11 | .header-icon { 12 | margin: 0 15px; 13 | 14 | i { 15 | font-size: 20px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Sidebar/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 侧边导航栏组件 3 | * @author Zhang Peng 4 | * @see https://ant.design/components/layout-cn/ 5 | */ 6 | import { Icon, Layout, Menu } from 'antd' 7 | import PropTypes from 'prop-types' 8 | import React from 'react' 9 | import { connect } from 'react-redux' 10 | import { matchPath, withRouter } from 'react-router' 11 | import { Link } from 'react-router-dom' 12 | import { bindActionCreators } from 'redux' 13 | 14 | import './Sidebar.less' 15 | import logoImg from './antd.svg' 16 | import { refreshMenu, refreshNavPath } from '../../../redux/actions/menu' 17 | 18 | const { Sider } = Layout 19 | 20 | const isActive = (path, history) => { 21 | return matchPath(path, { 22 | path: history.location.pathname, 23 | exact: true, 24 | strict: false 25 | }) 26 | } 27 | 28 | /** 29 | * 侧边导航栏组件。侧边栏采用的响应式布局方式,页面大小收缩到一定程度,侧边栏会隐藏。 30 | * @class 31 | */ 32 | class CustomSidebar extends React.PureComponent { 33 | static propTypes = { 34 | items: PropTypes.array 35 | } 36 | static defaultProps = { 37 | items: [] 38 | } 39 | 40 | state = { 41 | openKey: 'sub0', 42 | activeKey: 'menu0', 43 | mode: 'inline' 44 | } 45 | 46 | componentDidMount() { 47 | this.props.getAllMenu() 48 | } 49 | 50 | componentWillReceiveProps(nextProps) { 51 | Array.isArray(nextProps.items) && nextProps.items.map((item, i) => { 52 | Array.isArray(item.children) && item.children.map((node) => { 53 | if (node.url && isActive(node.url, this.props.history)) { 54 | this.menuClickHandle({ 55 | key: 'menu' + node.key, 56 | keyPath: ['menu' + node.key, 'sub' + item.key] 57 | }) 58 | } 59 | }) 60 | }) 61 | } 62 | 63 | menuClickHandle = (item) => { 64 | this.setState({ 65 | activeKey: item.key 66 | }) 67 | this.props.updateNavPath(item.keyPath, item.key) 68 | } 69 | 70 | render() { 71 | const { items, history } = this.props 72 | let { activeKey, openKey } = this.state 73 | 74 | const _menuProcess = (nodes, pkey) => { 75 | return Array.isArray(nodes) && nodes.map((item, i) => { 76 | const menu = _menuProcess(item.children, item.key) 77 | if (item.url && isActive(item.url, history)) { 78 | activeKey = 'menu' + item.key 79 | openKey = 'sub' + pkey 80 | } 81 | 82 | switch (item.type) { 83 | 84 | case 'SubMenu': 85 | return ( 86 | {item.title}} 89 | > 90 | {menu} 91 | 92 | ) 93 | case 'ItemGroup': 94 | return ( 95 | {item.title}} 98 | > 99 | {menu} 100 | 101 | ) 102 | case 'Divider': 103 | return ( 104 | 105 | ) 106 | case 'Item': 107 | default: 108 | return ( 109 | 110 | { 111 | item.url ? {item.icon && }{item.title} : 112 | {item.icon && }{item.title} 113 | } 114 | 115 | ) 116 | break 117 | } 118 | }) 119 | } 120 | 121 | const menu = _menuProcess(items) 122 | 123 | return ( 124 | /** 125 | * 响应式布局 126 | * 说明:配置 breakpoint 属性即生效,视窗宽度小于 breakpoint 时 Sider 缩小为 collapsedWidth 宽度, 127 | * 若将 collapsedWidth 设置为零,会出现特殊 trigger。 128 | */ 129 | 133 |
134 |
135 | 136 | Ant Design 137 |
138 |
139 | 145 | {menu} 146 | 147 |
148 | ) 149 | } 150 | } 151 | 152 | function mapStateToProps(state) { 153 | return { 154 | items: state.menu.items 155 | } 156 | } 157 | 158 | function mapDispatchToProps(dispatch) { 159 | return { 160 | getAllMenu: bindActionCreators(refreshMenu, dispatch), 161 | updateNavPath: bindActionCreators(refreshNavPath, dispatch) 162 | } 163 | } 164 | 165 | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CustomSidebar)) 166 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Sidebar/Sidebar.less: -------------------------------------------------------------------------------- 1 | .ant-layout-sider { 2 | height: 100%; 3 | width: 300px; 4 | } 5 | 6 | .ant-layout-logo { 7 | width: 200px; 8 | height: 64px; 9 | color: #108ee9; 10 | display: table-cell; 11 | vertical-align: middle; 12 | 13 | .logo-container { 14 | width: 150px; 15 | margin: 0 auto; 16 | 17 | img { 18 | width: 40px; 19 | height: 40px; 20 | margin-right: 12px; 21 | margin-top: 12px; 22 | } 23 | 24 | span { 25 | float: right; 26 | margin-top: 20px; 27 | font-size: 16px; 28 | font-family: Raleway, Hiragino Sans GB, sans-serif; 29 | text-transform: uppercase; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/reactapp/src/components/layout/Sidebar/antd.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | a 6 | Created with Sketch. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 33 | 34 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/reactapp/src/containers/Core/CoreContainer.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 应用的核心容器组件 3 | * @author Zhang Peng 4 | * @see https://ant.design/components/layout-cn/ 5 | */ 6 | import { Layout } from 'antd' 7 | import React from 'react' 8 | import { Redirect, Route } from 'react-router-dom' 9 | 10 | import './CoreContainer.less' 11 | import { authHOC } from '../../utils' 12 | import { ChildRoutes } from '../../routes' 13 | import { Content, Footer, Header, Sidebar } from '../../components' 14 | 15 | /** 16 | * 应用的核心容器组件 17 | *

控制整个页面的布局。整体采用的是侧边布局。

18 | * @class 19 | */ 20 | class CoreContainer extends React.PureComponent { 21 | render() { 22 | return ( 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | {ChildRoutes.map((route, index) => ( 31 | 32 | ))} 33 | 34 | 35 |