Web


基础

html书写规范

  1. 为每个HTML页面的第一行添加标准模式(standard mode)的声明,确保在每个浏览器中拥有一致的展现。

    <!DOCTYPE html>

    文档类型声明统一为HTML5声明类型,编码统一为UTF-8。

    <meta charset="UTF-8">
    <HEAD>中添加信息。
        <meta name="author" content="xxx@xxx.xxx">//作者
        <meta name="description" content="hello">//网页描述
        <meta name="keywords" content="a,b,c">//关键字,“,”分隔
        <meta http-equiv="expires" content="Wed, 26 Feb 1997 08:21:57GMT">//设定网页的到期时间。一旦网页过期,必须到服务器上重新调阅
        <meta http-equiv="Pragma" content="no-cache">//禁止浏览器从本地机的缓存中调阅页面内容
        <meta http-equiv="Window-target" content="_top">//用来防止别人在框架里调用你的页面
        <meta name="robots" content="none">//content的参数有all,none,index,noindex,follow,nofollow,默认是all
        <link rel="Shortcut Icon" href="favicon.ico">//收藏图标
        <meta http-equiv="Cache-Control" content="no-cache, must-revalidate">//网页不会被缓存IE支持通过特定
        //<meta>标签来确定绘制当前页面所应该采用的IE版本。除非有强烈的特殊需求,否则最好是设置为edge mode ,从而通知IE采用其所支持的最新的模式。
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    
  2. 非特殊情况下CSS样式文件外链至HEAD之间

    JAVASCRIPT文件外链至页面底部。

    <!DOCTYPE html>
    <html>
    <head>
    <link rel="stylesheet" href="css/main.css">
    </head>
    <body>
    <!-- 逻辑代码 -->
    <!-- 逻辑代码底部 -->
    <script src="lib/jquery/jquery-2.1.1.min.js"></script>
    </body>
    </html>
    
  3. 引入JAVASCRIPT库文件,文件名须包含库名称及版本号及是否为压缩版。

    jQuery-1.8.3.min.js

  4. 引入JAVASCRIPT插件, 文件名格式为库名称+.+插件名称。

    jQuery.cookie.js

  5. HTML属性应当按照以下给出的顺序依次排列,来确保代码的易读性。

    class
    id 、 name
    data-*
    src、for、 type、 href
    title、alt
    aria-*、 role
    
  6. 编码均遵循XHTML标准, 标签、属性、属性命名由小写英文、数字和_组成,且所有标签必须闭合,属性值必须用双引号””,

    避免使用中文拼音尽量简易并要求语义化。

    CLASS --> nHeadTitle --> CLASS遵循小驼峰命名法(little camel-case)
    ID --> n_head_title --> ID遵循名称+_
    NAME --> N_Head_Title --> NAME属性命名遵循首个字母大写+_
    
    <div class="nHeadTitle" id="n_head_title" name="N_Head_Title"></div>
    
  7. 当JAVASCRIPT获取单个元素时,通常使用document.getElementById来获取dom元素,document.getElementById兼容所有浏览器,但IE浏览器会混淆元素的ID和NAME属性,所以要区分ID和NAME命名。

    <input type="text" name="test">
    <div id="test"></div>
    <button onclick="alert(document.getElementById('test').tagName)"></button>
    <!-- ie6下为INPUT -->
    
  8. 特殊符号应使用转意符。

    < --> &lt;
    > --> &gt;
    空格 --> &nbsp;
    
  9. 含有描述性表单元素(INPUT,TEXTAREA)添加LABEL。

    <p>
    <label for="test">测试</label>
    <input type="text" id="test" />
    </p>
    
  10. 多用无兼容性问题的HTML内置标签,比如SPAN、EM、STRONG、OPTGROUP、LABEL等,需要自定义HTML标签属性时,首先考虑是否存在已有的合适标签可替换,如果没有,可使用须以“data-”为前缀来添加自定义属性,避免使用其他命名方式。

  11. 语义化HTML。

  12. 尽可能减少

    嵌套。

  13. 书写链接地址时避免重定向。

    href=”http://www.toutiao.com/“ //即在URL地址后面加“/”

  14. HTML中对于属性的定义,确保全部使用双引号,绝不要使用单引号

Web Api

API 设计方案

  1. Http的请求分为URL约定规则、请求参数规则
        
    URL规则: http://{server}/{product}/{version}/{logic}/{method}?{query_string}

    server: 为具体的服务域名
    product: 为应用工程名
    version: 为具体版本号, 便于将来的功能扩展, 可以暂定为 v1, v2
    logic: 为具体业务逻辑的初步划分, 比如后端管理方法, app端的请求方法
    method: 具体业务的方法

把 method 和 version 放到在URI中

    这样可以使API 版本化,方便版本控制,同时也便于日后API的分流
  1. Http的响应规则

    HTTP响应码为200, 返回结果为JSON字符串的形式:

    如果响应结果正确,则返回结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{  
      data : { // 请求数据,对象或数组均可
        user_id: 123,
        user_name: "zwz",
        user_avatar_url: "http://www.abc.com/1.jpg"
        ...
      },
      msg : "done", // 请求状态描述,调试用
      success : 1,
      code : 1001, // 业务自定义状态码
      extra : { // 其他扩展的数据,字段、内容不定
        type: 1,
        desc: "签到成功!"
      }
    }
如果响应结果失败,则返回如下结果:

    

1
2
3
4
5
6
7
8
9
{
      data : { // 请求数据,对象或数组均可
      },
      msg : "Internal Server Error", // 请求状态描述,调试用
      success : 0,
      code : 5001, // 业务自定义状态码
      extra : {
      }
    }
  1. Auth 权限验证

    API 的权限验证,有很多方案,目前成熟的OAuth 2.0框架等,不过 ,最简单的还是利用 Http Header 来完成这一目标。 将token 通过 Header 传递。来实现权限验证。

  2. API 在设计的时候,最好不要将业务错误码与HTTP状态码的绑定,重新定义一套业务错误码,来区分HTTP 的状态码。

    状态码的定义也最好有一套规范,类似于HTTP 的状态码,可以按照用户相关、授权相关、各种业务,做简单的分类。
        
        // Code 业务自定义状态码定义示例
        // 授权相关
        1001: 无权限访问
        1002: access_token过期
        1003: unique_token无效
        …

    // 用户相关
    2001: 未登录
    2002: 用户信息错误
    2003: 用户不存在

    // 业务相关
    3001: 业务XXX
    3002: 业务XXX

    // 系统异常
    5001:Internal Server Error

其他一些建议

  1. 规范统一的命名

    使用驼峰式或者下划线格式都可以,统一规范就行。不过,目前基本都是统一小写加下划线比较好。如:user_id,user_name,user_age等。

  2. 语义清晰,遵守常用缩写
          
    字段的名字最好能体现字段的类型,遵守一些常用的缩写,如:user_name, task_desc, date_str 等

  3. 空值、空字段的处理
          
    空值、空字段的处理也是比较容易出问题。统一空值用null 。除了布尔类型的,其余的空值统一用null表示,客户端保证每种字段的null可以被正常处理。 

  4. 各个Action 尽量符合CRUD操作的原则。   

  5. 给不同类型设置默认空值
          
    除了null,尽量对字段设置“默认值”,如

    数字就是0
    bool 类型的值,统一成数字0和1
    字符串就是空字符串""
    数组就是空数组[]
    对象就是空对象{}
    时间日期类型强制只能传标准GMT/UTC时间戳
    这样可以避免客户端处理空值产生的异常。
    
  6. 完整的URL

    API里面的数据也会有URL类型的,一般来说如用户的头像、各种图片、音频等资源,都是以URL链接的形式返回的。
          
      返回的URL一定要“完整”,主要指的是不要忘记URL里面的协议部分。应该是http://www.abc.com/1.jpg。

  7. REST 安全
          
    可以使用固有的 HTTP 基本验证,你还可以考虑通过支持表单验证,LTPA 验证,Open ID 验证等方式,来满足更多的企业安全要求。

  8. 尽量将API部署在专用域名之下。例如:https://api.example.com。

  9. API返回的数据格式,应该尽量使用JSON,避免使用XML。

  10. 返回正确 HTTP 响应代码,同时重新定义一套业务错误码,来区分HTTP 的状态码。

  11. 完善的文档,最好能自动生成在线API文档,这样文档能随时保持最新。
          
    例如:SwaggerUI。

接口安全和参数校验

  1. 一般通用的做法,是采用几步来保证接口和数据安全:
  • 首先一个是基于CA证书的HTTPS进行数据传输,防止数据被窃听;

  • 然后是采用参数加密签名方式传递,对传递的参数,增加一个加密签名,在服务器端验证签名内容,防止被篡改;

  • 最后是对一般的接口访问,都需要使用用户身份的token进行校验,只要检查通过才允许访问数据。

  1. 接口的访问方式,大概可以分为几类:
  • 使用用户名密码。

    这种方式比较简单,可以有效识别用户的身份(如包括用户信息、密码、或者相关的接口权限等等)。验证成功后,返回相关的数据。

  • 使用安全签名

    这种方式提交的数据,URL连接的签名参数是经过安全一定规则的加密的,服务器收到数据后也经过同样规则的安全加密,确认数据没有被中途篡改后,再进行数据修改处理。因此我们可以为不同客户端,如Web/APP/Winfrom等不同接入方式指定不同的加密秘钥,但是秘钥是双方约定的,并不在网络连接上传输,连接传输的一般是这个接入的AppID,服务器通过这个AppID来进行签名参数的加密对比。目前微信后台的回调处理机制,应该就是这么处理的。

  • 公开的接口调用

    不需要传入用户令牌、或者对参数进行加密签名的,这种接口一般较少,只是提供一些很常规的数据显示而已。

Jade

Jade 是一个高性能的模板引擎,它深受 Haml 影响,它是用 JavaScript 实现的,并且可以供 Node 使用。

使用

https://segmentfault.com/a/1190000000357534#articleHeader6

Jade代码

    doctype html
    html
      head
        title my jade template
      body
        h1 Hello

翻译成html为

    <!DOCTYPE html>
    <html>
      <head>
        <title>my jade template</title>
      </head>
      <body>
        <h1>Hello</h1>
      </body>
    </html>

例子

    #content
      .block
        input#bar.foo1.foo2

    ul#books
        li: a(href="#book-a") Book A

    p
      | foo bar
      | hello world

翻译成html

    <div id="content">
      <div class="block">
        <input id="bar" class="foo1 foo2"/>
      </div>
    </div>

    <ul id="books">
      <li><a href="#book-a">Book A</a></li>
    </ul>

    <p>
      foo bar
      hello world
    </p>

实战

引用js时如何防止缓存

  • 在js脚本中动态创建脚本

    在引用的网站中引入如下js:

    <script type="text/javascript"  >
        loadJs("http://localhost:8081/static/html/convention.js.js?timestamp="+Math.random(),null);
    </script>
    

    http://localhost:8081/static/html/convention.js.js 内容如下:

    loadJs("/static/js/convention.js?aaa=222", null);
    

    loadJs 就是创建JavaScript节点,实现如下:

    function loadJs(url, callback) {
        var done = false;
        var script = document.createElement('script');
        script.type = 'text/javascript';//do not 'application/javascript',because Low version of the browser is not compatible
        script.language = 'javascript';
        script.charset = "utf-8";
        script.src = url;
        //script.setAttribute('src', url);
        script.onload = script.onreadystatechange = function () {
            if (!done && (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete')) {
                done = true;
                script.onload = script.onreadystatechange = null;
                if (callback) {
                    console.log('load ' + url + ' success.');
                    callback.call(script);
                }
            }
        };
        document.getElementsByTagName("head")[0].appendChild(script);
    };
    

    以后修改bug时,只需要修改WEB-INF/static/html/convention.js.js中的版本号即可