I want to show an existing page(node) normally but return a HTTP404/410 etc instead of HTTP200.
How can I do it? Is there any simple way to do it?
Drupal Answers is a question and answer site for Drupal developers and administrators. It only takes a minute to sign up.
Sign up to join this communityI want to show an existing page(node) normally but return a HTTP404/410 etc instead of HTTP200.
How can I do it? Is there any simple way to do it?
for delivering 404 pages are useless to you. We can read:
Page callback functions wanting to report a "page not found" message should return
MENU_NOT_FOUND
instead of callingdrupal_not_found()
. However, functions that are invoked in contexts where that return value might not bubble up tomenu_execute_active_handler()
should calldrupal_not_found()
.
Of course if page callback will return MENU_NOT_FOUND
, it will not return any meaningful data. And while calling drupal_not_found()
does not always prevent data delivery, comments under function clearly shows that it causes double display of error message more often than any other result - not what you want, either.
may help you. Especially drupal_add_http_header()
. Let me emphasize one thing in it's description:
$value: The HTTP header value; if equal to FALSE, the specified header is unset. If $name is 'Status', this is expected to be a status code followed by a reason phrase, e.g. "404 Not Found".
So you want to set status to 404:
drupal_add_http_header('Status', '404 Not Found');
It should be enough, after all that's what drupal_deliver_html_page()
is doing when you use higher-level 404 calls from previous part of my answer.
Also, you might be interested in logging it like other 404 errors:
watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
It depends on what you need to decide if page should be 404 or not. If all you need is the actual data in page, you can go for hook_page_delivery_callback_alter()
:
This hook is intended for altering the delivery callback based on information unrelated to the path of the page accessed. For example, it can be used to set the delivery callback based on a HTTP request header (as shown in the code sample). To specify a delivery callback based on path information, use
hook_menu()
orhook_menu_alter()
.
emphasis mine.
and this means you need a node id. NID is part of the path, so, following suggestion quoted above, you want to use hook_menu_alter()
.
Let's take a look on how node's menu looks like. The part we want to alter is:
$items['node/%node'] = array(
'title callback' => 'node_page_title',
'title arguments' => array(1),
// The page callback also invokes drupal_set_title() in case
// the menu router's title is overridden by a menu link.
'page callback' => 'node_page_view',
'page arguments' => array(1),
'access callback' => 'node_access',
'access arguments' => array('view', 1),
);
What you need to do is to alter it to provide your own callback. In that callback:
HTTP 200 later
, so your status header should be delivered unaltered. Unless some modules will alter it, of course, but that's something we cannot know.Sending header might now work in any of the preprocess hooks or just about any tpl.php file. The fact that you could does not mean you should, especially not in tpl files, as it may interfere with caching, but it's worth to remember you are not limited to the ways I described above. For example hook_page_alter()
can be a safe choice, too.
Make sure the page size is more than 512 bytes, otherwise some browsers (Howdy, IE) will ignore it.
Keep in mind that by RFC 2616
User agents SHOULD display any included entity to the user.
As you may notice, this RFC uses MUST in some cases and this is not one of them, so if browser will refuse to display your page after you send 404, it's not exactly an error. Browsers are not forbidden to ignore your HTML when you send 404.
drupal_deliver_html_page()
, so I played on the safe side advising to do it there, too. Or where it's alter's api docs said to do it.
Put this inside of the node via PHP filter (which is usually a bad idea).
drupal_add_http_header('Status', '404 Not Found');
OR Put this inside of a hook_init call.
// Get the current active node object if present.
$node = menu_get_object();
if (!empty($node) && !empty($node->nid) && $node->nid == 86) {
drupal_add_http_header('Status', '404 Not Found');
}