iDomain - 基于Vue.js+MongoDB+Laravel 5.4的域名查询系统

标签(空格分隔): 项目


[TOC]

链接 d.jtup.cc

一、idea

why?

因为在老早以前还不太懂的时候,买了一个.com的域名,jtahstu.com,现在感觉太长了,并不太利于让别人记住,所以想换个简短的域名。

二、调研

how?

搜了下是否有查询域名是否已注册的接口,找到两三个,尝试了两种方式,最后使用的万网,也就是阿里云的接口,get一个地址,like this http://panda.www.net.cn/cgi-bin/check.cgi?area_domain=jtahstu.com,然后获取xml数据,解析即可。

ok (〃'▽'〃)

有了这个接口,后面就是遍历了,哈哈,ACM中最常用的方法,暴力搜索,这里是暴力查询。

so (o゚▽゚)o

下面就是要先写个爬虫,不断去拿阿里云接口的数据,然后存到MySQL数据库里。

then →_→

没注册的域名已经有了,下面就是先写个接口,让前端去调,前后分离嘛。这里后端就要考虑MongoDB记录缓存使用加密算法的数据传输访问频率限制搜索记录保存基于搜索习惯的优化查询防爬虫等问题了。

finaly 。◕ᴗ◕。

就剩前端的问题了,后端都是小case啦。移动端优先的原则,要写适配移动端的页面,本人前端菜的一批,可耻的使用了别人的模板,自己做了一些修改,能正常用,太炫酷的臣妾做不到啊。

前端在把基础模板搞定之后,使用vue.js,从后台获取数据,渲染页面,然后处理页面的搜索功能等。基本没几行jQuery代码,Vue大法好!!!

三、代码实现

1 爬虫

//请求http://panda.www.net.cn/cgi-bin/check.cgi?area_domain=jtahstu.com

<?xml version="1.0" encoding="gb2312"?>
<property>
    <returncode>200</returncode>
    <key>jtahstu.com</key>
    <original>211 : Domain name is not available</original>
</property>
//请求http://panda.www.net.cn/cgi-bin/check.cgi?area_domain=jtahstu.cn

<?xml version="1.0" encoding="gb2312"?>
<property>
    <returncode>200</returncode>
    <key>jtahstu.cn</key>
    <original>210 : Domain name is available</original>
</property>

不能跑太快,不然阿里云就给封IP了,本人是两次间隔0.5s,这都有点快,之前阿里云已经封过一次了,建议慢点。

2 后端

2.1 Controller

<?php

namespace App\Http\Controllers;

use App\Http\Common\Response;
use Illuminate\Http\Request;
use App\Http\Models\Domain;

class DomainController extends Controller
{
    public $key = "iDomain";

    /**
     * 首页
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function index(Request $request)
    {
        return view('domain');
    }

    /**
     * 搜索
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function ajax(Request $request)
    {
        $token = $request->input('_token');
        $str = trim($request->input('str'));
        $len = $request->input('len');
        $type = $request->input('type');

        if ($this->checkParameter($str,$len,$type)) {
            return Response::responseError('500', '参数错误');
        }
        if($str != 'jt'){
            self::writeLog($request->input());
        }

        $data = Domain::locateStr($str, $type, $len);
        return Response::responseAjax($data);
    }

    /**
     * 记录搜索记录
     * @param $data
     */
    public static function writeLog($data)
    {
        $data["add_time"] = date("Y-m-d H:i:s");
        $manager = new \MongoDB\Driver\Manager("mongodb://username:password@localhost:27017");

        $bulk = new \MongoDB\Driver\BulkWrite;
        $bulk->insert($data);
        $manager->executeBulkWrite('iApp.domain_log', $bulk);
        return true;
    }

    /**
     * 检查参数
     * @param $str
     * @param $len
     * @param $type
     * @return bool
     */
    public function checkParameter($str,$len,$type)
    {
        $strFlag = false;
        if (strlen($str) <= 0 || strlen($str) > 5 || !ctype_alpha($str))
            $strFlag = true;
        $lenFlag = !in_array($len, [4, 5]);
        $typeFlag = !in_array($type, ['cc', 'com']);
        return $strFlag || $lenFlag || $typeFlag;
    }


}

2.2 Model

<?php

namespace App\Http\Models;

use Illuminate\Database\Eloquent\Model;

class Domain extends Model
{
    protected $table = 'domain';
    protected $fillable = ['domain','type','num','len'];


    public static function locateStr($str,$type,$len)
    {
        return self::where('type','=',"$type")
            ->where('len','=',$len)
            ->whereRaw("locate('".$str."',domain)>0")
            ->orderBy('id','asc')
            ->select("domain","num","type")
            ->get()
            ->toArray();
    }
}

3 前端

页面太长了,主要是个js

/**
 * Created by jtahstu on 2017/9/2.
 */
csrf_token = document.querySelector('meta[name=jtahstu]').getAttribute('content');
window.isMobile = function() {
    var check = false;
    (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
    return check;
};

var vm = new Vue({
    delimiters: ['${', '}'],
    el: '#app',
    data: {
        domain_count: -1,
        domains: [],
        default_str: 'jt'
    },
    mounted: function () {
        this.$nextTick(function () {
            this.init();
        })
    },
    methods: {
        init: function () {
            this.postData(this.default_str)
        },
        search: function () {
            var word = document.getElementById("search_input").value;
            if (word.length > 0) {
                this.postData(word)
            }
        },
        postData: function (str) {
            Vue.http.options.emulateJSON = true;
            var _this = this;
            this.$http.post(
                "/domain/ajax",
                {str: str, type: "cc", len: 4, "_token": csrf_token}
            ).then(function (res) {
                // console.log(res.data.data);
                _this.domain_count = res.data.data.length;
                _this.domains = res.data.data
            })
        },
    },
    filters: {
        domainFilter: function (value) {
            return "https://wanwang.aliyun.com/domain/searchresult/?keyword=" + value.domain + "&suffix=." + value.type
        }
    }
});

$(function () {
    setTimeout(randomColor, 2000);
    $('#search-btn').click(function () {
        setTimeout(randomColor, 2000)
    });
    if(!isMobile()){
        $('#app').css("width","50%").css("margin-left","25%")
    }

    //input按回车键搜索
    $("#search_input").keydown(function(event) {
        if (event.keyCode == 13) {
            vm.search()
        }
    })
})

function randomColor() {
    $(".domain").each(function () {
        //随机变色
        $(this).css('color', '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).substr(-6));
    })
}

Vue.js真的好用,能省掉很多的jQuery代码,视图和数据的双向绑定很不错,而且完全可以充当模板引擎了,这里都没有用laravel自带的blade。

写着玩,熟悉下Vue和MongoDB,也让我挑选了一个比较中意的域名(jtup.cc),这就够了呀。

results matching ""

    No results matching ""