SORU
30 AĞUSTOS 2013, Cuma


Nasıl SPA SEO taranabilir yapmak için?

Taranabilir instructions bir SPA yapmak için çalışıyorum. Pek çok genel bir açıklama bile olsa, herhangi bir yerde gerçek örneklerle daha ayrıntılı bir adım adım öğretici bulamadım. Bu bitirdikten sonra diğerleri de yararlanabilir ve muhtemelen daha da artırabilir, böylece benim çözüm paylaşmak istiyorum.MVC Webapi kontrol ve Phantomjs sunucu tarafında, ve Durandal istemci tarafında ile push-state etkin; ben de kullanıyor Breezejs istemci-sunucu veri etkileşimi, ki ben şiddetle tavsiye ederim, ama denerim vermek genel bir açıklama yeterli olacak insanlara yardım da kullanarak diğer platformlar.

CEVAP
30 AĞUSTOS 2013, Cuma


Başlamadan önce, lütfen requires kullanımı özellikle google ne anladığınızdan emin olun . ben^>güzelve . ben^>çirkinUrl. Şimdi uygulamaya bakalım:

İstemci Tarafı

İstemci tarafında sadece sunucu ile dinamik olarak etkileşimde olduğu tek bir html sayfası AJAX çağrıları var. o yüzdendi. İstemci tarafında a etiketleri uygulamam dinamik olarak oluşturulur, daha sonra bu bağlantıları sunucu, google bot için görünür yapmak için nasıl göreceğiz. a her bir etiket o google bot crawl olacak pretty URL href bir etiketi olması gerekir. Seni istemiyorum href parçası olmak için kullanılan istemci tıklama üzerine (bile olsa yapmak istiyorum sunucu edebilmek için ayrıştırma, göreceğiz sonra), çünkü biz istemiyor olabilir yeni bir sayfa yüklemek için, sadece yapmak için bir AJAX arama bazı verileri görüntülenir bölümü sayfa değiştirmek ve URL ile javascript (örneğin kullanarak HTML5 pushstate Durandaljs). Yani, kullanıcı bağlantıyı tıklattığında iş yapar onclick google için iki href bir nitelik. push-state ben, şimdi, a tipik bir tag bu-URL # herhangi istemiyorum:<a href="http://www.xyz.com/#!/category/subCategory/product111" onClick="loadProduct('category','subCategory','product111')>see product111...</a>http://www.xyz.com/store/category/subCategory/product111. gibi sayfa mağaza gördüğünüz gibi Bu kısa ve basit bağlantılar tercih ediyorum çünkü. Ben orada benim aynı isimde bir kategori olmayacak anlamına gelir 'sayfaları, yani' 'hakkında'.onclick bölümü), arama üzerinden veri yüklemek için nasıl girmeyeceğim, çok iyi bir açıklama var. Kullanıcı bu linke tıkladığında, tarayıcı URL bu gibi bakmak istiyorum bahsetmek istiyorum tek önemli şey burada:http://www.xyz.com/category/subCategory/product111. Ve bu URL sunucuya gönderilmez. unutmayın, bu bir istemci ve sunucu arasındaki tüm etkileşimi AJAX, linkler, tüm üzerinden yapılır bir SPA! tüm sayfalar ' uygulandığını, istemci tarafında ve farklı bir URL değil arama yapmak için server (sunucu mu Peki kolu bu URL durumda onlar kullanılan harici linkler başka bir siteye sitenizi, göreceğiz daha sonra sunucu tarafı kısmı). Şimdi, bu harika Durandal tarafından işlenir. Ben şiddetle tavsiye ederim, aynı zamanda diğer teknolojileri isterseniz bu kısmı atlayabilirsiniz. Eğer sen seç, sen de kullanarak MS Visual Studio Express 2012 for Web gibi beni kurabilirsiniz Durandal Starter Kit ve shell.js, kullanmak gibi bir şey bu

define(['plugins/router', 'durandal/app'], function (router, app) {
    return {
        router: router,
        activate: function () {
            router.map([
                { route: '', title: 'Store', moduleId: 'viewmodels/store', nav: true },
                { route: 'about', moduleId: 'viewmodels/about', nav: true }
            ])
                .buildNavigationModel()
                .mapUnknownRoutes(function (instruction) {
                    instruction.config.moduleId = 'viewmodels/store';
                    instruction.fragment = instruction.fragment.replace("!/", ""); // for pretty-URLs, '#' already removed because of push-state, only ! remains
                    return instruction;
                });
            return router.activate({ pushState: true });
        }
    };
});

Burada belirtilmesi gereken birkaç önemli şey vardır:

  1. İlk rota (route:'' ile) ekstra veri var, yani http://www.xyz.com hangi URL için. Bu sayfada genel veri AJAX kullanarak yükleyin. Aslında a etiketleri bu sayfada olabilir. Google bot ile ne yapacağını bilir bu yüzden aşağıdaki etiketi eklemek istediğiniz:<meta name="fragment" content="!">. Bu etiket google bot göreceğiz bakalım hangi www.xyz.com?_escaped_fragment_= URL dönüşümü yapacaktır.
  2. 'Yol sadece diğer sayfalar' web uygulama isteyebilirsiniz. bağlantı için bir örnektir'
  3. Şimdi zor kısım 'kategori' rota, ve hiçbiri önceden tanımlanmış bir yol var birçok farklı kategoride olabilir. yok yani Bu mapUnknownRoutes giriyor. Bunun için bu bilinmeyen yolları haritaları 'store' rota ve aynı zamanda herhangi bir kaldırır '!' durumda URL pretty URL google arama motoru tarafından üretilen. 'Yol' parça 'özelliği ve AJAX çağrı veri almak için yapar, görüntüler ve URL yerel olarak değiştirmek. bu bilgi alır' mağaza Benim uygulamada, her tür aramak için farklı bir sayfa yüklemek istemiyorum; ben sadece bu verileri ilgili olduğu sayfanın bir bölümünü değiştirmek ve aynı zamanda URL, yerel olarak değiştirin.
  4. Durandal devlet URL push kullanmayı öğretir pushState:true dikkat edin.

Bu istemci tarafında ihtiyacımız olan şey. Ayrıca karma URL (Durandal seni bunun için pushState:true Kaldır basit) uygulanabilir. Daha karmaşık kısmı (en azından benim için...) sunucu kısmıydı:

Sunucu Tarafı

WebAPI denetleyicileri ile sunucu tarafında MVC 4.5 kullanıyorum. Sunucu gerçekten ihtiyacı kolu 3 tip URLs: olanlar tarafından oluşturulan google - hem pretty ugly ve ayrıca bir 'basit' URL ile aynı biçimi gibi görünen istemci tarayıcısında. Sağlar bunun nasıl yapılacağı hakkında bak:

Pretty Url ve 'basit' olanları ilk halinde var olmayan bir kontrolör referans için çalışıyor sanki sunucu tarafından yorumlanır. Sunucu http://www.xyz.com/category/subCategory/product111 gibi bir şey görür ve denetleyici adlı arar 'kategori'. web.config aşağıdaki satırı özel hata işleme denetleyicisi için bu yönlendirmek için ekledim:

<customErrors mode="On" defaultRedirect="Error">
    <error statusCode="404" redirect="Error" />
</customErrors><br/>

Şimdi, bu bir şey için URL gibi dönüştürür: http://www.xyz.com/Error?aspxerrorpath=/category/subCategory/product111. İstediğim URL gönderilmesi için istemcisi yükleme verileri üzerinden AJAX, asıl hüner burada çağırmak için varsayılan dizin ' Denetleyicisi gibi herhangi bir referans denetleyicisi; ben bunu . ben^>eklemekarma için önce tüm URL 'kategori' ve 'alt kategori' parametreleri; karma URL gerektirmez herhangi bir özel kontrolör dışında varsayılan dizin ' denetleyici ve veri gönderilir istemci sonra kaldırır karma ve kullandığı bilgi sonra karma için yük veri ile AJAX. Burada hata işleyicisi denetleyicisi kodu:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

using System.Web.Routing;

namespace eShop.Controllers
{
    public class ErrorController : ApiController
    {
        [HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions, AcceptVerbs("PATCH"), AllowAnonymous]
        public HttpResponseMessage Handle404()
        {
            string [] parts = Request.RequestUri.OriginalString.Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
            string parameters = parts[ 1 ].Replace("aspxerrorpath=","");
            var response = Request.CreateResponse(HttpStatusCode.Redirect);
            response.Headers.Location = new Uri(parts[0].Replace("Error","")   string.Format("#{0}", parameters));
            return response;
        }
    }
}

Çirkin Url? Bu google bot tarafından oluşturulur ve kullanıcı tarayıcı gördüğü tüm verileri içeren düz HTML dönmelidir. Bunun için phantomjs kullanıyorum. Hayalet başsız bir tarayıcı sunucu tarafında istemci tarafında - ama ne yaptığını yapıyor. Diğer bir deyişle, phantom bilir (diğer şeylerin arasında) nasıl bir web sayfası üzerinden bir URL ayrıştırma dahil olmak üzere çalışan tüm javascript kodu olarak alma veri ile AJAX çağrıları) ve ver sana geri yansıtır HTML DOM. Eğer MS Visual Studio Express kullanıyorsanız size birçok link) bu hayali kurmak istiyor.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace eShop.App_Start
{
    public class AjaxCrawlableAttribute : ActionFilterAttribute
    {
        private const string Fragment = "_escaped_fragment_";

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var request = filterContext.RequestContext.HttpContext.Request;

            if (request.QueryString[Fragment] != null)
            {

                var url = request.Url.ToString().Replace("?_escaped_fragment_=", "#");

                filterContext.Result = new RedirectToRouteResult(
                    new RouteValueDictionary { { "controller", "HtmlSnapshot" }, { "action", "returnHTML" }, { "url", url } });
            }
            return;
        }
    }
}

Bu 'filterConfig.denir'de'': . App_start cs

using System.Web.Mvc;
using eShop.App_Start;

namespace eShop
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new AjaxCrawlableAttribute());
        }
    }
}

Çünkü AjaxCrawlableAttribute' yolları bir denetleyici 'adlı HtmlSnapshot', ve burada bu denetleyici: . çirkin URL gördüğünüz gibi

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace eShop.Controllers
{
    public class HtmlSnapshotController : Controller
    {
        public ActionResult returnHTML(string url)
        {
            string appRoot = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);

            var startInfo = new ProcessStartInfo
            {
                Arguments = String.Format("{0} {1}", Path.Combine(appRoot, "seo\\createSnapshot.js"), url),
                FileName = Path.Combine(appRoot, "bin\\phantomjs.exe"),
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                RedirectStandardInput = true,
                StandardOutputEncoding = System.Text.Encoding.UTF8
            };
            var p = new Process();
            p.StartInfo = startInfo;
            p.Start();
            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();
            ViewData["result"] = output;
            return View();
        }

    }
}

Associated 49* *çok basit bir kod sadece bir satır@Html.Raw( ViewBag.result )createSnapshot.js adında gördüğünüz gibi seo adlı yarattım. İşte bu javascript dosyası:

var page = require('webpage').create();
var system = require('system');

var lastReceived = new Date().getTime();
var requestCount = 0;
var responseCount = 0;
var requestIds = [];
var startTime = new Date().getTime();

page.onResourceReceived = function (response) {
    if (requestIds.indexOf(response.id) !== -1) {
        lastReceived = new Date().getTime();
        responseCount  ;
        requestIds[requestIds.indexOf(response.id)] = null;
    }
};
page.onResourceRequested = function (request) {
    if (requestIds.indexOf(request.id) === -1) {
        requestIds.push(request.id);
        requestCount  ;
    }
};

function checkLoaded() {
    return page.evaluate(function () {
        return document.all["compositionComplete"];
    }) != null;
}
// Open the page
page.open(system.args[1], function () { });

var checkComplete = function () {
    // We don't allow it to take longer than 5 seconds but
    // don't return until all requests are finished
    if ((new Date().getTime() - lastReceived > 300 && requestCount === responseCount) || new Date().getTime() - startTime > 10000 || checkLoaded()) {
        clearInterval(checkCompleteInterval);
        var result = page.content;
        //result = result.substring(0, 10000);
        console.log(result);
        //console.log(results);
        phantom.exit();
    }
}
// Let us check to see if the page is finished rendering
var checkCompleteInterval = setInterval(checkComplete, 300);

Ben ilk temel kodu nereden aldığımı sayfa için Thomas Davis teşekkür etmek istiyorum :-).checkLoaded() fonksiyon true değerini döndürür kadar. sayfa tutar Bu yüzden mi? çünkü bu benim özel SPA kılan birkaç AJAX çağrısı için tüm veri ve yer yer DOM benim sayfa ve hayali olamaz biliyorum tüm görüşmeleri tamamlamadan önce bana geri dönen HTML yansıma DOM. Burada yaptığım şey son AJAX eğer bu etiket DOM tamamlandıktan biliyorum varsa o ** 55, Ekle diyoruz sonra. Yanıt olarak bu 56 ** olay Durandal, daha fazlası için here görmek istiyorum. Bu 10 saniye (en çok için sadece bir saniye sürer) PES içinde olmazsa. HTML döndürülen kullanıcı tarayıcıda gördüğü tüm bağlantıları içerir. Komut dosyası bir HTML anlık görüntüsü var <script> etiketleri doğru URL referans değil çünkü düzgün çalışmaz. Bu değiştirilebilir de javascript hayalet dosya, ama ben sanmıyorum ki bu gerekli, çünkü HTML snapshort sadece kullanılan google a bağlantılar ve çalıştırmak için javascript; bu bağlantılar . ben^>yapıngüzel bir referans URL, ve aslında, eğer seni görmeye HTML anlık bir tarayıcı, sen-ecek almak javascript hataları ama tüm bağlantılar düzgün çalışmaz ve doğrudan sunucuya bir kez daha güzel bir URL hoşuna gidiyor, tam çalışma sayfası.http://www.xyz.com/store/category/subCategory/product111. Bu sorunu önlemek içinde benim çözüm tüm geçersiz URL tedavi edilir gibi onlar aslında çağrıları için 'dizin' denetleyici ve sanırım bu olabilir ele sonra içinde 'store' denetleyici olmadan ek web.config gösterdim yukarıda.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Alfredo Garcia

    Alfredo Garc

    25 Mayıs 2007
  • Justin Davis

    Justin Davis

    14 Ocak 2008
  • WK

    WK

    9 Ocak 2006