I implemented AMP pages and they are indexed with no errors and appear in Google search. When a visitor clicks on a link on Google SERP then they appear on Google Analytics (including cached pages) as referenced from organic/google. But when a visitor clicks on a link on that AMP page then the referrer is sometimes expected referral/ampprogect.org and in many cases direct/none.
Of course, amp-analytics is set.
I suspect that direct/none appear when AMP pages served from the main server in response to a click from cached page.
Just in case, AMP were published a few days ago and not all have been discovered by now.
Does it make any sense?
Amp-analytics is implemented in a very basic way
<amp-analytics type="googleanalytics">
<script type="application/json">
{
"vars": {
"account": "UA-XXXXX-Y" //real account id for sure
},
"triggers": {
"trackPageview": {
"on": "visible",
"request": "pageview"
}
}
}
</script>
</amp-analytics>
Update
I set up Google Tag Manager for AMP and changed amp-analitics block with
<amp-analytics config="https://www.googletagmanager.com/amp.json?id=GTM-zzzzzz>m.url=SOURCE_URL" data-credentials="include"></amp-analytics>
with the same result.
The click from cached AMP page (that is https://google.com/mydomain-com.cdn...) to non-amp shows referral/ampproject.org and click on non-cached AMP (that is https : //mydomain.com/amp/something.aspx) shows direct/none.
Thanks to this great post I understood what goes wrong and applied the ideas to .NET. The main idea is to catch amp-analytics configuration object (JSON formatted) and replace it with my own (with clientId inside).
First I created HttpHandler
''//.VB
Namespace AmpHandlers
Public Class AmpConfig
Implements IHttpHandler
Private Const unixStart As DateTime = #1/1/1970# ''//start of epoc
Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
Public Sub ProcessRequest(context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.Clear()
''//ecpected request
''// https : //mydomain.com/gtm-amp.json?id=GTM-zzzzzz>m.url=SOURCE_URL
If String.IsNullOrEmpty(context.Request.QueryString("id")) OrElse context.Request.QueryString("id") <> "GTM-zzzzzz" Then
''//no answer
context.Response.End()
Return
End If
Dim clientId As String = ""
If context.Request.Cookies("_ga") IsNot Nothing Then
Dim ga As String = context.Request.Cookies("_ga").Value ''//GA1.2.12321354.1507250223
clientId = Regex.Match(ga, "(\d+?\.\d+?$)").Groups(1).Value
Else
Dim rand As New Random()
''//Majic 2147483647 is upper limit of Google's random part of _ga cookie
''//The second part is Unix time, in seconds
clientId = rand.Next(2147483647) & "." & CInt(DateTime.UtcNow.Subtract(unixStart).TotalSeconds)
End If
''//Set cookie and response headers
context.Response.ContentType = "application/json" '; charset=UTF-8
context.Response.SetCookie(New HttpCookie("_ga") With {.Value = "GA1.2." & clientId,
.Path = "/", .Domain = context.Request.Url.Host, .Expires = DateTime.UtcNow.AddYears(2)
})
context.Response.AddHeader("Access-Control-Allow-Origin", "https://mydomain-com.cdn.ampproject.org")
context.Response.AddHeader("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin")
context.Response.AddHeader("AMP-Access-Control-Allow-Source-Origin", "https://" & context.Request.Url.Host)
context.Response.AddHeader("Access-Control-Allow-Source-Origin", "https://" & context.Request.Url.Host)
context.Response.AddHeader("Access-Control-Allow-Credentials", "true")
context.Response.AddHeader("Content-Disposition", "attachment; filename=""GTM-NZPM27T.json""")
context.Response.AddHeader("cache-control", "no-cache, no-store, must-revalidate")
''//https://www.googletagmanager.com/amp.json?id=GTM-zzzzzz>m.url=SOURCE_URL response is saved locally and edited
''//possibly it is not the best colution
Dim sr As New IO.StreamReader(context.Server.MapPath("~/amp-gtm.config"))
Dim str As String = sr.ReadToEnd()
str = str.Replace("[[clientId]]", clientId)
context.Response.Write(str)
context.Response.Flush()
context.Response.End()
End Sub
End Class
End Namespace
Next I registered it in web.config.
<handlers>
<add name="amp-gtm" verb="GET" path="gtm-amp.json" type="AmpHandlers.AmpConfig" resourceType="Unspecified"/>
</handlers>
and finally put into amp-analytics tag.
<amp-analytics config="https : //mydomain.com/gtm-amp.json?id=GTM-zzzzzz>m.url=SOURCE_URL" data-credentials="include"></amp-analytics>
Now all clicks from cached and non-cached AMP pages show organic/google.
Related
I have written an asp.net http handler that returns javascript. When including a script tag on html page that references this handler, chrome/firefox is not reporting the cache-control:max-age header being returned unless a querystring (or '?') is present in the script tag src. Thus the handler is being hit every time. This is happening in both firefox and chrome.
Here is the handler implementation:
Public Overrides Async Function ProcessRequestAsync(context As HttpContext) As Task
Dim loader As New ScriptLoader(context)
Dim sb As New StringBuilder()
sb.Append(Await loader.GetScriptsAsync())
sb.Append(loader.GetLoaderScript("engine"))
sb.Append(loader.GetLoaderScript("styles"))
Dim script As String = sb.ToString()
context.Response.ContentType = "application/javascript"
context.Response.Cache.SetCacheability(HttpCacheability.Public)
context.Response.Cache.SetMaxAge(TimeSpan.FromHours(12))
context.Response.Write(script)
End Function
HTML script tag:
<div>
<script src="/ListingDisplay/loader/js"></script>
</div>
Results:
https://i.ibb.co/hK8TQJ3/Capture.png
When I append a "?" on the script source:
<div>
<script src="/ListingDisplay/loader/js?"></script>
</div>
I get the expected results, and the handler is not hit on subsequent requests:
Expected Result:
https://i.ibb.co/x8S3W3v/Capture.png
Anyone ever seen this? Any ideas?
In my code I'm sending a HttpWebRequest to a page in my website.
When request sends to this page, It doesn't maintain the Session values.
Below is the code, from where I'm generating the web request:
Public Overloads Shared Function ReadURL(ByVal sUrl As String) As String
Dim sBody As String
Dim oResponse As HttpWebResponse
Dim oRequest As HttpWebRequest
Dim oCookies As New CookieContainer
oRequest = WebRequest.Create("http://localhost:64802/inventory/purchase_order.aspx?id=5654")
oRequest.CookieContainer = oCookies
oResponse = oRequest.GetResponse()
Dim oReader As New StreamReader(oResponse.GetResponseStream())
sBody = oReader.ReadToEnd
oReader.Close()
oResponse.Close()
Return sBody
End Function
Below is the code written on Page_Load of Purchaseorder.aspx.vb:
iDomains_ID = Session("Domains_ID")
iLogin_ID = Session("Login_ID")
sPage = Request.Path
If Request.QueryString.Count > 0 Then sPage &= "?" & Request.QueryString.ToString()
sPage = shared01.Encrypt(sPage, Application("PK"))
If Not User.Identity.IsAuthenticated Or iLogin_ID = 0 Then
Response.Redirect("/login.aspx?page=" & sPage)
Exit Sub
End If
Above code doesn't gets the session values and it redirects to the login page.
So, how i can maintain the session on both pages during HttpWebRequest.
Looking for your replies.
EDIT
I've tried to use CookieContainer class as you can see in above code. But it doesn't work at all.
As an alternative, assuming the calling and called pages are in the same application, you could use the Server.Execute method to load the content of the page without making a separate request to the site:
Public Overloads Function ReadURL(ByVal sUrl As String) As String
Using writer As New StringWriter()
Server.Execute("~/inventory/purchase_order.aspx?id=5654", writer, False)
Return writer.ToString()
End Using
End Function
If I've understood you correctly, you're making a request from one page in your site to another, and you want to send the cookies from the current HttpRequest with your WebRequest?
In that case, you'll need to manually copy the cookies to the CookieContainer:
For Each key As String In Request.Cookies.AllKeys
Dim sourceCookie As HttpCookie = Request.Cookies(key)
Dim destCookie As New Cookie(sourceCookie.Name, sourceCookie.Value, sourceCookie.Path, "localhost")
destCookie.Expires = sourceCookie.Expires
destCookie.HttpOnly = sourceCookie.HttpOnly
destCookie.Secure = sourceCookie.Secure
oCookies.Add(destCookie)
Next
NB: You'll either need to make the ReadUrl function non-Shared, or pass the current HttpRequest as a parameter.
You'll also need to make sure the calling page has EnableSessionState="false" in the <%# Page ... %> directive, otherwise the page you're calling will hang trying to obtain the session lock.
Your code seems like you will need to make a request and a post. The first request will redirect you to your login page. The second will be a request where you post to the login page, which will start the session and (?) store information into the session variables. That post (to the login page) will then redirect you to the page you want.
I used code in this example http://www.codeproject.com/Articles/145122/Fetching-ASP-NET-authenticated-page-with-HTTPWebRe (I tweaked it a bit) to write an application to do this.
I have a bit of strange behaviour in an asp.net web application that involves the session state being lost.
Process
A user logs into the application and the session is set. They then fill out 1 field, and the application then does an AJAX POST to a .asmx web service. Within the web service, I am using a HttpWebRequest to grab data from another server.
This data is then output to the browser.
A few more fields are then filled in, and the data is then again Post to the same web service via an AJAX POST.
Problem
Straight after the HttpWebRequest, I grab the username from a session variable. This works.
On the next AJAX request however, the session no longer exists.
While testing this, I removed the stage at which the HttpWebRequest is called and my session is never lost. So for some reason, the session is removed AFTER my first AJAX POST and before the second AJAX POST only if I am running the HttpWebRequest code.
Code
I am not doing anything fancy in the code. Just doing a simple jQuery AJAX Post
$.ajax({
url: method,
data: params,
type: "POST",
contentType: "application/json; charset=utf-8", dataType: "json",
success: function (data) {
// handle data
},
error: function(xhr,status,error) { }
});
Creating a System.Net.HttpWebRequest and then getting the System.Net.HttpWebResponse out of that.
Then reading a session variable dim username as string = Session(_SESSION_USERNAME).ToString()
I have never noticed this behaviour before when using HttpWebRequest before (not using any AJAX though)
Function Backfill(value As String) As Details
Dim details As Details = Nothing
Dim appSettings As ConfigSettings.AppConfig = ConfigSettings.AppConfig.getConfig()
Dim url As String = appSettings.Settings.BackfillUrl
Dim username As String = appSettings.Settings.BackfillUser
Dim password As String = appSettings.Settings.BackfillPass
Dim expParameters As String = ""
Dim xml As XmlDocument = Nothing
Dim xmlHttp As XMLHTTP = Nothing
Dim nodeList As XmlNodeList = Nothing
Dim node As XmlNode = Nothing
Dim response As String = ""
Dim success As String = ""
'
' REMOVED TO HIDE INFO
expParameters = "<PARAMETERS>" & _
"</PARAMETERS>"
Try
xmlHttp = New XMLHTTP()
xmlHttp.open("POST", url)
xmlHttp.Send(expParameters)
response = xmlHttp.responseText()
xml = New XmlDocument
xml.LoadXml(response)
SaveExperianFile(xml, value)
nodeList = xml.DocumentElement.ChildNodes
node = nodeList.Item(0)
success = node.Attributes.GetNamedItem("success").Value.ToString.Trim
If success.ToLower.Trim = "y" Then
details = SetDetails(xml)
End If
Catch ex As Exception
Finally
If Not xmlHttp Is Nothing Then
xmlHttp.Dispose()
xmlHttp = Nothing
End If
End Try
Return details
End Function
edit
The XMLHTTP Class code can be seen here http://codepaste.net/ymnqsf
edit
Seems as though something strange is happening when I am saving the XMLDocument to my file system.
Private Sub SaveExperianFile(xml As XmlDocument, value As String)
Dim appConfig As ConfigSettings.AppConfig = ConfigSettings.AppConfig.getConfig()
Try
xml.Save(HttpContext.Current.Server.MapPath(appConfig.Settings.SavePath & value & "_backfill.xml"))
Catch ex As Exception
End Try
End Sub
If I don't call this method, then the session is always set.
Question
Do you know what is causing this behaviour?
Can you check if you just loose the session or the whole application is restarted. If you are saving the XML in the virtual directory / web application folder then it might case web application to restart. If many dozen files were added in short succession to each other, that would be a case to restart the App Pool.
just a hunch, but maybe you need to maintain cookies across HttpWebRequests.
have a look at this question for more help.
Http web request doesn't maintaining session
I want to get domain name not for remote ip. i have two domain(website). example www.a1.com and www.a2.com. in a2 domain send a request to a1 domain's page like GetRequest.ashx
the example of http request is
http://www.a1.com/GetRequest.ashx?username=bala&password=123456
in my GetRequest.ashx page example coding
<%# WebHandler Language="VB" Class="Handler" %>
Imports System
Imports System.Web
Public Class GetRequest : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/plain"
Dim username As String = context.Request.QueryString("username")
Dim password As String = context.Request.QueryString("password")
**'//Here i need a coding to get requested domain name that is who send the request to my page**
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
i already use the following coding but not solve my problem. because it return ip address. i need domain only not for ip.
context.Request.ServerVariables("REMOTE_ADDR")
context.Request.ServerVariables("REMOTE_HOST")
Dim domain As String
Dim url As Uri = HttpContext.Current.Request.Url
domain = url.AbsoluteUri.Replace(url.PathAndQuery, String.Empty)
the variable domain contain www.a1.com but i need www.a2.com
use google analytics api to solve my problem? then how to use this api can any one explain
Page.Request.Url.Host contains the host name of the url (www.a1.com in your example)
If a request on the www.a2.com site calls a page on the www.a1.com site, the hostname will always be www.a1.com since that is the host that was used to call the page. I recommend passing a query string variable if you need to know that the request originated from www.a2.com.
You can access the request object through HttpContext, like so:
EDIT: Changed to get host name of referring URL
string host = HttpContext.Current.Request.UrlReferrer.Host;
EDIT: UrlReferrer is returning null. Alternative using HTTP_REFERER:
if (!String.IsNullOrEmpty(Request.ServerVariables["HTTP_REFERER"]))
{
Uri referringUrl = new Uri(Request.ServerVariables["HTTP_REFERER"]);
string referringHostName = referringUrl .Host;
}
Check the Referrer:
HttpContext.Current.Request.UrlReferrer.Host
Inside your code:
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/plain"
Dim username As String = context.Request.QueryString("username")
Dim password As String = context.Request.QueryString("password")
**'//Here i need a coding to get requested domain name that is who send the request to my page**
Dim domain as string = context.Request.UrlReferrer.Host
End Sub
I have a directory of images that reside outside the context of my web application that I need to serve to the user. Currently I'm using an IHttpHandler to serve the images and using some javascript to navigate through a set of images (the navigation is primitive for now). I followed examples for using IHttpHandler to serve images closely but when I view the images in firefox the browser hangs and when I view in IE I get a "Stack overflow at line: 0".
Code for the IHttpHandler
Public Class ShowImage : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) _
Implements IHttpHandler.ProcessRequest
Dim picid As String
If context.Request.QueryString("id") IsNot Nothing Then
picid = context.Request.QueryString("id")
Else
Throw New ArgumentException("No parameter specified")
End If
'' Convert Byte[] to Bitmap
context.Response.Cache.SetCacheability(HttpCacheability.NoCache)
context.Response.Cache.SetNoStore()
context.Response.Cache.SetExpires(DateTime.MinValue)
Dim newBmp As Bitmap = GetPhoto(picid)
If newBmp IsNot Nothing Then
Dim imgGraphics As Graphics = Graphics.FromImage(newBmp)
imgGraphics.DrawImageUnscaled(newBmp, 0, 0, 640, 480)
context.Response.StatusCode = 200
context.Response.ContentType = "image/jpeg"
newBmp.Save(context.Response.OutputStream, ImageFormat.Jpeg)
newBmp.Dispose()
Else
'' Return 404
context.Response.StatusCode = 404
context.Response.End()
End If
End Sub
...
Public ReadOnly Property IsReusable() As Boolean _
Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class
Here is the javascript code that's calling the IHttpHandler defined above:
function updateImage(){
var ddlPhotos = document.getElementById("ddlPhotos");
var selected = ddlPhotos.options[ddlPhotos.selectedIndex].value;
if( selected != -1 ){
// Update the image
retrievePicture(document.getElementById("propertyImage"), selected)
}
}
function retrievePicture(imgCtrl, picid)
{
imgCtrl.src = 'ShowImage.ashx?id=' + picid;
}
Finally here's the img tag that is the "place holder":
<img src="#"
alt="Property Photo"
width="640px"
height="480px"
id="propertyImage"
onload="retrievePicture(this, '<%= pictureId.value %>');"
/>
I'm confused as to why the javascript seems to spiral out of control...
My guess - not being a JavaScript expert - is that the onload event is triggered any time the image finishes loading. In other words, as soon as the image is loaded, it triggers loading a new one... which triggers loading a new one... which triggers loading a new one etc.
You will probably be able to see that in multiple calls to the server for the same image - unless the browser is caching it, of course. Anyway, you'll either need to trigger it in some other way, or make the trigger detect that the image which has been loaded is already the right one, and there's no need to replace it.
I suspect the act of changing the src and loading a new image may be triggering the "onload" event of the image again.
Try clearing the event before setting the source, will probably look similar to this:
function retrievePicture(imgCtrl, picid)
{
imgCtrl.onload = null;
imgCtrl.src = 'ShowImage.ashx?id=' + picid;
}