关于JS原型.原性链的总结整理
- /******** 自定义构造函数 ********/
- function Fun(){}
- var foo=new Fun();
- foo.constructor==Fun()
- //也就是说自定义Fun函数的prototype原型就是foo实例的间接原型!自定义function的原型将继承Object
- /******** 实例对象可以直接使用__proto__找到构造器使用的prototype ********/
- foo.__proto__==foo.construtor.prototype;
- //true, 但是,__proto__属性在IE浏览器中一直到IE11才被支持
- /******** 自定义函数和原型的关系 ********/
- function c(){}
- c.prototype
- ->c {}
- --->constructor: function()
- --->proto: Object //对象继承的原型
- ============================================================================
- c.constructor //c本身已经是构造器了
- function Function() { [native code] }
- Function.prototype //构造函数Function的原型,如果没有特殊定义就是空function
- function (){}
- ============================================================================
- /******** 布尔值实例 ********/
- true.constructor
- function Boolean(){ [native code] }
- Boolean.prototype
- -> Boolean{ [[PrimitiveValue]]: false}
- --->constructor: function Boolean()
- --->toString: function toString()
- --->valueOf: function valueOf()
- ---> proto : Object //对象继承的原型
JS 遍历图片路径取得图片名并重新拼接
- var arr=[
- {
- "picSrc": "http://code.liuxinxiu.com/upload/user/1460273594384A3577E4_c.jpg",
- "name": "贤惠的含羞草",
- "age": "36岁",
- "stature": "164cm",
- "character": "顾家",
- "info": "寻找北京的男生",
- "distance": "3.0km"
- },
- {
- "picSrc": "http://code.liuxinxiu.com/upload/user/1470127527444A8EF6B2_c.png",
- "name": "微微笑",
- "age": "28岁",
- "stature": "164cm",
- "character": "可爱",
- "info": "寻找北京 28~40岁的男生",
- "distance": "1.2km"
- }
- ];
- /******** 循环取得获取图片名称 ********/
- for(i in arr){
- if(arr[i].picSrc){
- var reg = /.*\/([^\.\/]+)/g;
- var fileName=arr[i].picSrc.replace(reg,"$1");
- arr[i].picSrc='http://code.liuxinxiu.com/upload/user/'+fileName; //重新赋值再转为JSON.字符串
- //console.log('http://code.liuxinxiu.com/upload/user/'+fileName); //重新拼接
- //console.log(fileName); //正则获取最后一个字符
- }
- };
- JSON.stringify(arr);
适用于LINUX下批量下载图片
React - ES6 - Ajax获取接口数据渲染到UI组件【完整示例】
本站PHP后端接口: http://code.liuxinxiu.com/php/Interface/Jsoncallback.php?GUID=1&&Jsoncallback=1
本实例用 ES5 + JSX 语法编写[对应实例] : http://liuxinxiu.com/React_Ajax_setState_Render_UI_ES5/
- /****** ES6输入文件[调用模块依赖] ******/
- import React, { Component, PropTypes } from 'react'
- import $ from 'n-zepto'
- /****** ES5输入文件[调用模块依赖] ******/
- //var React=require('react');
- //var $=require('n-zepto');
- //import * as from './commentList.js'
- //import list from './commentList.js';
- /****** 本地模拟Array数据******/
- var movies = [
- {
- id: 1,
- name: '速度与激情001',
- date: 2011
- },
- {
- id: 2,
- name: '速度与激情002',
- date: 2009
- }
- ];
- /****** 外部子组件map数组当做模板之用 ES5 + JSX 语法编写 ******/
- var MoviesList = React.createClass({
- render: function () {
- // this.props 用于从组件外部传入数据
- var _movies = this.props._movies;
- return (
- <li className="datali">
- {_movies.id}-{_movies.name}
- </li>
- )
- }
- });
- /****** 外部子组件map数组当做模板之用 ES6 + JSX 语法编写 ******/
- let CommentList=class CommentList extends Component {
- constructor(props) {
- super(props); //ES6调用父类构造函数super不能少!
- this.state = {
- wording: '你好呀, '
- };
- }
- /****** Ajax子组件中[主体模板] ******/
- render(){
- return <ul>{this.props.comments.map(this.renderComment)}</ul>;
- }
- /****** Ajax子组件中[嵌套模板] ******/
- renderComment({plat,type,name,guid,cre_time,lottery}){
- return (
- <li>{plat}--{type}--{name}--{guid}--{cre_time}--{lottery}</li>
- )
- }
- }
- /****** 使用ES6 + JSX 语法编写 class xx extends React.Component{} 创建一个组件 ******/
- class CommentListContainer extends Component {
- /****** [ES6-constructor||ES5-getInitialState] ******/
- constructor(){
- super();
- this.state = {
- loading: true,
- title: '我喜欢的电影',
- movies: [],
- comments: []
- }
- }
- componentDidMount(){
- $.ajax({
- type: 'GET',
- url: 'http://code.liuxinxiu.com/php/Interface/Jsoncallback.php',
- data: {GUID:'1'},
- dataType:'jsonp', //告诉Ajax调用$jsonp
- jsonp: "Jsoncallback", //zpeto-1.2支持自定义回调名
- success: function(data){
- var yy=JSON.stringify(data);
- var tlist=JSON.stringify(data.enttityList);
- //console.log(tlist);
- //console.log(this.state.title+'22');
- this.setState({
- comments:data.enttityList,
- lottery:data.enttityList[0].lottery
- });
- var commentsStr=JSON.stringify(this.state.comments);
- console.log("\n--->>commentsStr:\n"+commentsStr); //查看获取的数据
- //console.log(this.state.comments+'33')
- }.bind(this),
- error: function(xhr, type){
- alert(xhr+type+'Ajax error!');
- }
- });
- //console.log(this.state.comments+'++++--!!'); //ajax底下拿不到结果因为提前于异步
- }
- render(){
- return <CommentList comments={this.state.comments}/>;
- }
- }
- /****** ES5输出给router ******/
- //module.exports=DemoComponent;
- /****** ES6输出给router ******/
- export default CommentListContainer;
React - ES5 - Ajax获取接口数据渲染到UI组件【完整示例】
本站PHP后端接口: http://code.liuxinxiu.com/php/Interface/Jsoncallback.php?GUID=1&&Jsoncallback=1
本实例用 ES6 + JSX 语法编写[对应实例] : http://liuxinxiu.com/React_Ajax_setState_Render_UI_ES6/
- //import React, { Component, PropTypes } from 'react'
- //import $ from 'n-zepto'
- var React=require('react'); //Es-5
- var $=require('n-zepto'); //Es-5
- //import * as from './commentList.js'
- //import list from './commentList.js';
- /****** 外部子组件map数组当做模板之用 ******/
- var MoviesList = React.createClass({
- render: function () {
- // this.props 用于从组件外部传入数据
- ar _movies = this.props._movies;
- return (
- <li className="datali">
- {_movies.id}-{_movies.name}
- </li>
- )
- }
- });
- /****** 本地模拟Array数据******/
- var movies = [
- {
- id: 1,
- name: '速度与激情001',
- date: 2011
- },
- {
- id: 2,
- name: '速度与激情002',
- date: 2009
- }
- ];
- /****** 使用Es5语法 React.createClass 创建一个组件 ******/
- var DemoComponent = React.createClass({
- /****** 使用 getInitialState 的返回值作为数据的默认值 ******/
- getInitialState: function () {
- // this.state 用于存储数据comments被Ajax赋值要先定义个名称
- return {
- loading: true,
- title: '我喜欢的电影',
- movies: [],
- comments: []
- }
- },
- componentDidMount: function() {
- $.ajax({
- type: 'GET',
- url: 'http://code.liuxinxiu.com/php/Interface/Jsoncallback.php',
- data: {GUID:'1'},
- dataType:'jsonp', //告诉Ajax调用$jsonp
- jsonp: "Jsoncallback", //zpeto-1.2支持自定义回调名
- success: function(data){
- var yy=JSON.stringify(data);
- var tlist=JSON.stringify(data.enttityList);
- console.log(tlist);
- //console.log(this.state.title+'22')
- this.setState({
- comments:data.enttityList,
- lottery:data.enttityList[0].lottery
- });
- var slist=JSON.stringify(this.state.comments);
- console.log(slist)
- //console.log(this.state.comments+'33')
- }.bind(this),
- error: function(xhr, type){
- alert(xhr+type+'Ajax error!'); //error
- }
- });
- //console.log(this.state.comments+'++++--!!'); //ajax底下拿不到结果因为提前于异步
- },
- render: function () {
- // this.state 用于存储当前的数据
- var comments = this.state.comments;
- //var dataHtml=movies.map(<p>{name}</p>);// 注意这里 bind(this) 修正了上下文
- /****** Movies子模板 ******/
- function renderMovies({id,name}){
- return <li>{id}-{name}</li>;
- }
- /****** Movies大模板[内嵌子模板] ******/
- //var dataHtml = movies.map(renderMovies);
- /****** Movies大模板[外调子模板] ******/
- var dataHtml = movies.map(function(movies){
- return (
- <MoviesList _movies={movies}/>
- )
- }.bind(this));// 注意这里 bind(this) 修正了上下文
- //console.log('movies:'+movies+'--'+'dataHtml:'+dataHtml);
- /****** Ajax子模板******/
- function renderComment({plat,type,name,guid,cre_time,lottery}){
- return <li>{plat}--{type}--{name}--{guid}--{cre_time}--{lottery}</li>;
- }
- /****** Ajax大模板 ******/
- var AjaxHtml = this.state.comments.map(renderComment);
- //var AjaxHtml='11'
- console.log('comments:'+comments+'--'+'AjaxHtml:'+AjaxHtml);
- return (
- <ul>{AjaxHtml}</ul>
- )
- }
- });
- /****** ES5输出给router ******/
- module.exports=DemoComponent;
- /****** ES6输出给router ******/
- //export default DemoComponent;
使用ES5||ES6 -- 输入文件示例 [调用所依赖的模块]:
- /****** ES5调用依赖模块[require]被打包会自动生成关联代码 ******/
- var MyComponent = require('./components/movie-list');
- /****** ES6调用依赖模块 ******/
- import MyComponent from './components/movie-list';
使用ES5||ES6 -- 输出文件示例[输出给被依赖模块]:
- /****** ES5输出给router ******/
- module.exports=DemoComponent;
- /****** ES6输出给router ******/
- //export default DemoComponent;
使用ES5 -- 创建一个组件:
- /****** 使用Es5语法 React.createClass 创建一个组件 ******/
- var DemoComponent = React.createClass({
- /****** 使用 getInitialState 的返回值作为数据的默认值(!return) ******/
- getInitialState: function () {
- return {
- loading: true,
- title: '我喜欢的电影',
- // 注意这里将 外部传入的数据赋值给了 this.state
- movies: []
- }
- },
- /****** 输出HTML模板,此处可以调用子组件******/
- render: function () {
- return (
- <div className="component-hello">
- {this.state.title}
- </div>
- )
- }
- });
使用ES5 -- map遍历当前Array并调用渲染数据的[外部]子组件:
- /****** 使用Es5语法 遍历数组并调用外部子组件 ******/
- var MoviesList=React.createClass({...});
- var dataHtml = movies.map(function(movies){
- return (
- <MoviesList _movies={movies}/>
- )
- }.bind(this));// 注意这里 bind(this) 修正了上下文
- return (
- <ul>{dataHtml}</ul>
- )
- /****** 外部子组件map数组当做模板之用 ******/
- var MoviesList = React.createClass({
- render: function () {
- // this.props 用于从组件外部传入数据
- var _movies = this.props._movies;
- return (
- <li className="datali">
- {_movies.id}-{_movies.name}
- </li>
- )
- }
- });
使用ES5 -- map遍历当前Array并调用渲染数据的[内部]子组件:
- /****** 使用Es5语法 遍历数组并调用内部子组件 ******/
- function renderMovies({id,name}){
- return <li>{id}-{name}</li>;
- }
- var dataHtml = movies.map(renderMovies);
- return (
- <ul>{dataHtml}</ul>
- )
Ajax获取接口数据并设置到state :
- componentDidMount(){
- $.ajax({
- type: 'GET',
- url: 'http://code.liuxinxiu.com/php/Interface/Jsoncallback.php', //JSONP接口
- data: {GUID:'1'},
- dataType:'jsonp', //告诉Ajax调用$jsonp
- jsonp: "Jsoncallback", //zpeto-1.2支持自定义回调名
- success: function(data){
- var yy=JSON.stringify(data);
- var tlist=JSON.stringify(data.enttityList);
- //console.log(tlist);
- //console.log(this.state.title+'22');
- this.setState({
- comments:data.enttityList,
- lottery:data.enttityList[0].lottery
- });
- var commentsStr=JSON.stringify(this.state.comments);
- console.log("\n--->>commentsStr:\n"+commentsStr); //查看获取的数据
- //console.log(this.state.comments+'33')
- }.bind(this),
- error: function(xhr, type){
- alert(xhr+type+'Ajax error!');
- }
- });
- //console.log(this.state.comments+'++++--!!'); //ajax底下拿不到结果因为提前于异步
- }
react 的事件调用分类
- 触摸事件:onTouchCancel\onTouchEnd\onTouchMove\onTouchStart
- (只会在移动设备上接受)
- 键盘事件:onKeyDown\onKeyPress\onKeyUp
- 剪切事件:onCopy\onCut\onPaste
- 表单事件:onChange\onInput\onSubmit
- 焦点事件:onFocus\onBlur
- UI元素:onScroll(移动设备是手指滚动和PC的鼠标滑动)
- 滚动事件:onWheel(鼠标滚轮)
- 鼠标类型:onClick\onContextMenu(右键)\onDoubleClick\onMouseDown\onMouseEnter\
- onMouseLeave\onMouseMove\onMouseOut\onMouseOver\onMouseUp
- onDrag\onDrop\onDragEnd\onDragEnter\onDragExit\onDragLeave\onDragOver\onDragStart
react 嵌套路由相关
/src/js/app.js
- import React, { PropTypes, Component } from 'react';
- import {render} from 'react-dom'; //render((_component),Dom);
- //import ReactDOM from 'react-dom'; //ReactDOM.render((_component),Dom);
- import getRouter from './getRouter';
- import { Router, Route, Link, IndexRoute, hashHistory } from 'react-router';
- /* using an ES6 transpiler, like babel */
- //import { createHistory } from 'history/createBrowserHistory'
- //import createBrowserHistory from 'history/createBrowserHistory';
- /* Import Component */
- import Hello from '../components/hello/hello.jsx'
- import Other from '../components/other/other.jsx'
- /* ensure test */
- require.ensure(['./test'],function(require){
- var aModule = require('./test');
- console.log("xxxx");
- },'test');
- /* create history for router */
- //const history = createHistory()
- /* Router Config */
- render((
- <Router history={hashHistory}>
- <Route path="/" component={getRouter}>
- <IndexRoute component={Hello} />
- <Route path="other" component={Other} />
- </Route>
- </Router>
- ), document.getElementById('app'));
/src/js/getRouter.js
- import React, { PropTypes, Component } from 'react';
- export default React.createClass ({
- render() {
- return <div>
- {this.props.children}
- </div>
- }
- });
/src/components/hello/hello.jsx
- import React, { PropTypes, Component } from 'react';
- /* 导入组件样式hello.css */
- import styles from './css/hello.css';
- //require("./css/hello.css");
- class Hello extends React.Component {
- render(){
- return (
- <div className="hello">
- <p>Hello World!!!!!!!...</p>
- <p>cll不错!</p>
- </div>
- );
- };
- };
- export default Hello;
/src/components/other/other.jsx
- class Other extends React.Component {
- render() {
- return (
- <div>
- <p>this is other component!!!</p>
- <p>111111111cll不错!</p>
- </div>
- )
- }
- }
- export default Other;
NodeJS反向代理至后端数据接口
支持来自任何域名的Post请求,验证请求参数必须有: [name、gender] 否则直接JSON返回错误!
- var http=require('http');
- function server(){
- this.exec=function(route,req,res){
- var _self=this;
- /********** 获取客户端数组中的部分数据可向后多取 **********/
- this.arrv=function(o,n,p){
- var i,y,d,p;y=false;d='';
- for(i in o){
- if(o[i]==n&&p==undefined){i++;return o[i]};
- if(o[i]==n&&p!=undefined&&!isNaN(p)||y){
- var s;s=i;
- p=Number(p);
- if(p>0){
- p--;s++;d+=o[s];y=true;
- }
- else{
- return d;
- }
- }
- }
- };
- /********** 请求后端时可获取单个header头内地信息 **********/
- this.getReqHeaders=function(n){
- if(typeof(n)=='undefined'){
- console.log('getReqHeaders(n)变量没有定义!');
- }else{
- return _self.arrv(req.rawHeaders,String(n));
- }
- };
- /******** 获取客户端请求的header整体头部信息 ********/
- this.rawHeaders=function(state){
- var json={};
- if(!state){
- for(var i=0;i<req.rawHeaders.length;i++){
- var s,s=i;
- if(i%2==0){
- s++;json[req.rawHeaders[i]]=req.rawHeaders[s];
- }
- }
- }
- if(state){
- for(var i=0;i<req.rawHeaders.length;i++){
- json[i]=req.rawHeaders[i];
- }
- }
- var jsonStr=JSON.stringify(json);//结果:"{'1':'a','2':'b','3':'c'}"
- var jsonObj=JSON.parse(jsonStr); //结果:[object Object]
- return jsonObj;
- };
- //接收参数 ------ sreq.on("data",function(data){});接收html中ajax传递的参数
- req.on("data",function(data){
- /********* 打印提示||接受数据并反向代理到后端 *********/
- console.log("\n--->>\nReq.on('data')",req.method.toUpperCase()+" Use Proxy!");
- /********* 使用代理||这里Post请求体是回调data *********/
- send(route,req,res,data);
- });
- /********** 判断是GET请求类型||也可以代理给后端处理 **********/
- if(req.method.toUpperCase()=="GET"){
- var params=[];
- //params=url.parse(request.url,true).query;
- //params['fruit']=compute(params);
- res.writeHeader(200,{
- "Content-type":"text/html; charset=utf-8"
- });
- res.write('<h1>It is forbidden for the URL request!</h1>');
- res.write('<hr><address>NodeJs/'+process.version);
- res.write(' at '+req.headers.host.split(':')[0]);
- res.write(' Port '+req.headers.host.split(':')[1]+'</address>');
- res.end();
- }
- /********* 如有req.on("data",function(data){});就跳过了以下方法 ******/
- /********* 判断是POST请求类型||提交不走代理此方法是本机处理回调 **********/
- else if(req.method.toUpperCase()=='POSTo'){
- var postData="";
- /********** 读取Post提交的数据 **********/
- req.addListener("data",function(data){
- postData+=data;
- });
- /********** 数据读取完毕就会执行的监听 *********/
- req.addListener("end",function(){
- /********* 定义Post请求主体 *********/
- var query=require('querystring').parse(postData);
- /************** 判断如果有POST过来数据 *************/
- if(query.name&&query.gender){
- console.log('Start a request...');
- var origin=_self.arrv(req.rawHeaders,'Origin');
- console.log("origin:"+typeof req.rawHeaders+'---')
- /********** 代理转发至php,跨域全放开让后端去匹配验证 **********/
- //res.setHeader('Access-Control-Allow-Origin','*');
- //res.setHeader('Access-Control-Allow-Headers','X-Requested-With');
- //res.setHeader('Access-Control-Allow-Methods','GET,POST,PUT,DELETE,OPTIONS');
- //send(route,req,res,query);
- }
- /****** 判断结束 ******/
- });
- }
- /******** 请求后端接口 ********/
- function send(route,req,res,data){
- /***************************************
- var data={
- name:'liuxinxiu',
- gender:"male",
- time:new Date().getTime()
- };
- ****************************************/
- //data=require('querystring').stringify(data);
- var rawHeaders=_self.rawHeaders();
- /********** 判断一个对象是哪中类型的对象 **********/
- function isArray(obj){
- return Object.prototype.toString.call(obj)==='[object Array]';
- };
- /********* 打印Request Headers **********/
- console.log("\n--->>\nRequest Headers:",req.rawHeaders);
- /***** 向后端发送请求基本的设置 *****/
- var options={
- port: 80,
- host:"code.liuxinxiu.com",
- path:'/php/Post/CORS_PHP.php',
- method: 'POST',
- headers:{
- 'Content-Type':_self.getReqHeaders('Content-Type'),
- 'Content-Length':data.length,
- 'Origin':_self.getReqHeaders('Origin'),
- 'User-Agent':_self.getReqHeaders('User-Agent')
- }
- };
- /***** 如果header整体替换就会乱码 *****/
- //options.headers=_self.rawHeaders();
- var request=http.request(options,function(result){
- console.log("\n--->>\nstatusCode:",result.statusCode);
- console.log("\n--->>\nResponse Headers:",result.headers);
- if(result){
- var content_type,origin,x_powered_by,server;
- //content_type=origin=x_powered_by=server=undefined;
- content_type=result.headers['content-type'];
- origin=result.headers['access-control-allow-origin'];
- x_powered_by=result.headers['x-powered-by'];
- server=result.headers['server'];
- /********** 判断分别加入包含服务器错误页 **********/
- if(origin!=undefined&&result.statusCode==200){
- res.setHeader('Access-Control-Allow-Origin',origin);
- }
- if(content_type!=undefined){
- res.setHeader('Content-Type',content_type);
- }
- if(x_powered_by!=undefined){
- res.setHeader('X-Powered-By',x_powered_by);
- }
- if(server!=undefined){
- res.setHeader('Server',server);
- }
- }
- /********** 有异常的请求需要问题定位 **********/
- if(result.statusCode<200||result.statusCode>206){
- }
- /********** 接受数据数据监听 **********/
- var _data='';
- result.on('data',function(chunk){
- _data+=chunk;
- });
- /********** 结束接受数据监听 *********/
- result.on('end',function(){
- console.log("\n--->>\nresult:",_data);
- res.write(_data);
- res.end();
- });
- /******** request逻辑完成 ********/
- });
- request.on('error',function(e) {
- console.log('problem with request: ' + e.message);
- });
- //request.write(data);
- request.write(data+"\n");
- request.end();
- }
- /****** 内部结束 ******/
- }
- }
- module.exports=new server();
NodeJS数据接口(Post请求直接代理至后端PHP): http://liuxinxiu.com:3000/CORS_Node_Proxy/
PHP数据接口(验证跨域提交白名单外返回错误): http://code.liuxinxiu.com/php/Post/CORS_PHP.php
http 200 from cache vs 304 not modified
在讨论这个问题之前先了解一下浏览器的缓存机制。浏览器的缓存机制有两种,一种是“Freshness(新鲜度,过期机制)”,另一种是“Validation(校验值,验证机制)”。
Nginx 静态文件缓存相关配置
- location ~ \.( html|js|css|png|gif|jpg|jpeg|bmp|swf)$ {
- #如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到 upstream负载均衡池中的另一台服务器,实现故障转移
- proxy_next_upstream http_502 http_504 error timeout invalid_header;
- proxy_cache cache_one;
- #对不同的HTTP状态码设置不同的缓存时间
- proxy_cache_valid 200 10m;
- proxy_cache_valid 304 1m;
- proxy_cache_valid 301 302 1h;
- proxy_cache_valid any 1m;
- #以域名、URI、参数组合成Web缓存的Key值,Nginx根据Key值哈希
- proxy_cache_key $host$uri$is_args$args;
- proxy_set_header Host $host;
- proxy_set_header X-Forwarded-For $remote_addr;
- #如果没有缓存则通过proxy_pass转向tomcat请求
- proxy_pass http://tomcat_server_pool;
- }
Nginx upstream 相关配置
Nginx_upstream实现:设置备份主机及过滤HTTP错误自动切除[8000=>Node服务器 || 2000=>默认错误处理页]:
- #集群中的所有后台服务器的配置信息
- upstream nodeJs {
- #server 123.56.233.208 weight=10;
- #server 127.0.0.1:3000 weight=10;
- server 127.0.0.1:8000;
- server 127.0.0.1:2000 backup;
- }
- #调用所有的Server配置文件
- include /usr/local/nginx/conf/vhosts/*.conf;
- server {
- listen 3000;
- server_name liuxinxiu.com;
- add_header Proxy-By $upstream_http_server; #代理服务器Server
- location / {
- proxy_pass http://nodeJs; #反向代理到后端Server
- proxy_set_header Host $host:3000;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- #proxy_next_upstream error timeout invalid_header http_403 http_404;
- }
- }
Nginx=>2000端口默认错误处理页(相关配置):
- server{
- listen 2000;
- server_name 127.0.0.1;
- index index.html index.htm index.php;
- root /ftp/www/2000;
- error_page 404 /index.html;
- }