Ostatnio napisałem jak można odebrać i wysłać pingback, teraz pora na coś starszego – Trackback (specyfikacja). Został on wymyślony na początku XXI wieku przez firmę SixApart i zaimplementowany w MovableType. Z tego co się orientuje, to na pewno nie był on wspierany przez Bloggera – teraz nie wiem jak jest.

Ogólnie ja rozumiem to tak – Pingback coś nowego, Trackback – coś starego. Jednak wciąż niektóre serwisy wysyłają trackbacks i nie posiadają implementacji pingback. Jeżeli chcemy śledzić kto do nas linkuje, to najlepiej jest zaimplementować obydwa linkbacki.

Implementacja

Z Trackback jest dużo prościej niż z pingback, ze względu na to, iż wykorzystuje on model REST i odbieranie następuje poprzez HTTP POST/PUT (warto zaimplementować to i to). Dzięki czemu nie musimy tworzyć żadnych serwisów itp., wystarczy akcja w MVC lub odpowiednie WebAPI.

Plusem trackbacka jest to, że możemy mieć ID naszego postu, przez co nie trzeba się męczyć z weryfikacją po urlu, ale o tym napiszę w sekcji wykrywania.

Samo odebranie trackback jest proste:

// http://www.sixapart.com/labs/trackback/
// http://www.movabletype.org/documentation/trackback_manual.html
[AcceptVerbs("POST", "PUT")]
public ActionResult Trackback(string blog_name, 
    string url,
    string title,
    string excerpt, 
    int id)
{
    var model = new TrackbackInput
    {
        blog_name = blog_name,
        url = url,
        title = title,
        excerpt = excerpt
    };

    if (model.url.IsNullOrWhiteSpace())
    {
        return TrackbackError("URL Is Missing");
    }

    var post = GetPostById()(id);

    // checks if post exists
    if (post == null)
    {
        return RedirectToAction("AllPosts", "Posts");
    }

    var postUrl = Url.Action("Details", "PostDetails", post.ToRouteData());
    // same as with pingback, checks if url exists on target site
    if (postUrl.ExistsOn(model.url) == false)
    {
        return TrackbackError("The source page does not link");
    }

    var comments = GetComments(post.CommentsId);
            
    if (comments.AreCommentsClosed()|| post.AllowComments == false)
    {
        return TrackbackError("Comments closed");
    }
            
    var trackbackExists = comments.UrlExists(model.url);

    if (trackbackExists)
    {
        return TrackbackError("Trackback already registered");
    }

    var comment = new PostComments.Comment();

    comment.IsSpam = _akismetService.CheckForSpam(comment);

    if (comment.IsSpam)
    {
        // do something with spam
    }
    else
    {
        // do something with not spam
        // like add to comments
    }

    return TrackbackSuccess();
}

Wykorzystuje tutaj dwie pomocnicze metody zwracające wynik w postaci XML – success zawiera element error i wartość zero, zaś error, element error i wartość tekstową (warto o tym pamiętać przy wysyłaniu):

private ActionResult TrackbackError(string error)
{
    var response = new XDocument(
        new XElement("response",
            new XElement("error", error)
        )
    );

    return XDoc(response);
}

private ActionResult TrackbackSuccess()
{
    var response = new XDocument(
        new XElement("response",
                        new XElement("error", "0")
                    )
    );

    return XDoc(response);
}

ps. XDoc to metoda pomocnicza zwracająca XML z XDocument.

Autowykrywanie

By zewnętrzne serwisy wiedziały o tym, że nasz blog odbiera trackbacki, do każdego postu/strony dla której chcemy zezwolić dodawanie trackback, musimy wygenerować mniej więcej taki o to kod HTML:

<!-- this needs to be a comment block -->
<!-- dc: http://dublincore.org/documents/dces/  -->
<!--

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
         xmlns:dc="http://purl.org/dc/elements/1.1/"
         xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
         <rdf:Description 
                rdf:about="LINK_TO_POST" 
                dc:identifier="UNIQUE_LINK_TO_POST" 
                dc:title="POST_TITLE" 
                trackback:ping="OUR_TRACKBACK_URL_WITH_POST_ID" />
</rdf:RDF>

-->

Można to wykonać na przykład za pomocą extension method:

public static class HtmlExtensions
{
    public static MvcHtmlString TrackbackRdf(this HtmlHelper html, PostViewModel post)
    {
        if (post.AreCommentsClosed || post.Post.IsCommentAllowed == false)
        {
            return MvcHtmlString.Create(string.Empty);
        }

        var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
        var postUrl = urlHelper.AbsoluteAction("Details", "PostDetails", post.Post.ToRouteData());
        var trackbackUrl = urlHelper.AbsoluteAction("Trackback", "Services", new
        {
            id = post.Post.Id
        });

        return MvcHtmlString.Create(GetTrackbackRdf(postUrl, post.Post.Title, trackbackUrl));
    }

    // i think I did downloaded this code from somewhere...
    private static string GetTrackbackRdf(string postUrl, MvcHtmlString postTitle, string trackbackUrl)
    {
        var sb = new StringBuilder();
        sb.AppendLine(@"<!--");
        sb.AppendLine(@"<rdf:RDF xmlns:rdf=""http://www.w3.org/1999/02/22-rdf-syntax-ns#"" ");
        sb.AppendLine(@"xmlns:dc=""http://purl.org/dc/elements/1.1/"" ");
        sb.AppendLine(@"xmlns:trackback=""http://madskills.com/public/xml/rss/module/trackback/"">");
        sb.AppendLine(@"<rdf:Description ");
        sb.AppendLine(@"rdf:about=""{0}"" ".FormatWith(postUrl));
        sb.AppendLine(@"dc:identifier=""{0}"" ".FormatWith(postUrl));
        sb.AppendLine(@"dc:title=""{0}"" ".FormatWith(postTitle));
        sb.AppendLine(@"trackback:ping=""{0}"" />".FormatWith(trackbackUrl));
        sb.AppendLine(@"</rdf:RDF>");
        sb.AppendLine("-->");

        return sb.ToString();
    }
}

Podsumowanie

Implementacja jest dużo prostsza niż przy pingback, jednak wymaga ekstra kodu na stronie, niektórzy tego nie lubią. W WordPress na przykład przez powinien czas usunęli w ogóle metodę która umożliwiała generowanie rdf – ale potem szybko ją przywrócili ;) ale zostałam poruszona pewna kwestia na którą też warto zwrócić uwagę – niektóre blogi, mogą udostępniać trackback, ale poprzez element link rel=trackback.

To tyle, następnym razem napiszę jak można taki trackback wysłać.

A wy korzystanie z trackbacków czy z pingabacków? Czy wam to wszystko jedno? ;)

2 KOMENTARZE

  1. A czemu akcja nie przyjmuje bezpośrednio TrackbackInput ?

    Mi wszystko jedno czy trackback czy pingback bo mimo lektury wszystkich twoich postów na ten temat nadal nie wiem czym się różnią i… don’t care;)

  2. Z TrackbackInput wiaze sie historia… w testach integracyjnych po prostu nie dzialal. Jest to zapewne wina model bindera, ale zamiast meczyc sie nim pozostawilem to tak jak jest teraz.

    na przyklad taki o to kod:

    var client = new RestClient(“http://localhost:8848/”);
    var request = new RestRequest(“trackback/1569”, Method.POST);
    request.AddParameter(“blog_name”, “some_value”);
    request.AddParameter(“url”, “some_value”);
    request.AddParameter(“title”, “some_value”);
    request.AddParameter(“excerpt”, “some_value”);

    powodowal, ze model mial wszystkie wartosci null, a w ten sposob jest wysylany trackback.

    Zas co do roznicy… jak dalej nie wiesz to znaczy ze dobrze. Roznicy pomiedzy trackback a pingback nie ma – jest roznica pomiedzy protokolami ale to wszystko. Jak sie czlowiek wysili to mozna zaobserwowac dwie male roznice (jezeli je roznicami mozna nazwac) jakie ja widze to: Trackback musi miec url, a pingback jest autowykrywalny za pomoca header.

    oraz trackback jest bardziej podatny na spam ze wzgledu na parametry typu `excerpt`

Comments are closed.